Execute the parallel processing Args: iterable_inputs: iterable inputs to be processed process_function: function to process each item of iterable_inputs usage_counter: instance to count and estimate the token and time usage of model
(
self,
iterable_inputs: Iterable[Any],
process_function: Callable[[Any], Any],
usage_counter: ModelUsageCounter = None,
n: int = 1,
buffer: TaskBuffer = None,
**kwargs
)
| 25 | self.timeout = timeout |
| 26 | |
| 27 | def execute( |
| 28 | self, |
| 29 | iterable_inputs: Iterable[Any], |
| 30 | process_function: Callable[[Any], Any], |
| 31 | usage_counter: ModelUsageCounter = None, |
| 32 | n: int = 1, |
| 33 | buffer: TaskBuffer = None, |
| 34 | **kwargs |
| 35 | ) -> Any: |
| 36 | """ |
| 37 | Execute the parallel processing |
| 38 | |
| 39 | Args: |
| 40 | iterable_inputs: iterable inputs to be processed |
| 41 | process_function: function to process each item of iterable_inputs |
| 42 | usage_counter: instance to count and estimate the token and time usage of model |
| 43 | n: number of samples advanced each time usage is estimated, especially when iterable_inputs are batched. |
| 44 | e.g. iterable_inputs = [[1, 2, 3], [4, 5, 6], ..., [22, 23]], then n=3 |
| 45 | **kwargs: additional arguments for process_function, which are fixed for each iteration |
| 46 | """ |
| 47 | # load buffer |
| 48 | if buffer: |
| 49 | results: list = buffer.load(usage_counter) |
| 50 | remain = len(iterable_inputs) - len(results) |
| 51 | if remain < 0: |
| 52 | raise Exception(f"Number of iterable inputs ({len(iterable_inputs)}) is less than the number of results in buffer ({len(results)})!") |
| 53 | elif remain > 0: |
| 54 | results = results + [None] * remain |
| 55 | else: |
| 56 | results = [None] * len(iterable_inputs) |
| 57 | |
| 58 | # set usage counter |
| 59 | if usage_counter: |
| 60 | usage_counter.set_parallel() |
| 61 | kwargs["usage_counter"] = usage_counter |
| 62 | |
| 63 | with ThreadPoolExecutor(max_workers=self.n_workers) as executor: |
| 64 | future_to_idx = { |
| 65 | executor.submit(process_function, inp, **kwargs): idx for idx, inp in enumerate(iterable_inputs) if not buffer or not buffer.detail_progress[idx] |
| 66 | } # filter out processed samples (process all if no buffer) |
| 67 | |
| 68 | st = time.time() |
| 69 | try: |
| 70 | for future in as_completed(future_to_idx, timeout=self.timeout): |
| 71 | try: |
| 72 | result = future.result() |
| 73 | # ensure the order of the results is preserved. |
| 74 | index = future_to_idx[future] |
| 75 | results[index] = result |
| 76 | |
| 77 | # estimate the token and time usage |
| 78 | if usage_counter: |
| 79 | usage_counter.set_parallel_time(time.time() - st) |
| 80 | usage_counter.estimate_usage(n=n) |
| 81 | |
| 82 | if buffer: |
| 83 | buffer.add_progress([index]) |
| 84 | buffer.save(results, usage_counter) |
no test coverage detected