(function: Callable[[int], T], num_threads: int | None = None)
| 37 | |
| 38 | |
| 39 | def run_parallel(function: Callable[[int], T], num_threads: int | None = None) -> dict[int, T]: |
| 40 | num_threads = get_num_threads(num_threads) |
| 41 | |
| 42 | barrier = threading.Barrier(num_threads) |
| 43 | results = {} |
| 44 | errors = {} |
| 45 | |
| 46 | def wrapper(thread_id: int): |
| 47 | try: |
| 48 | barrier.wait() |
| 49 | results[thread_id] = function(thread_id) |
| 50 | except Exception as exception: |
| 51 | errors[thread_id] = exception |
| 52 | |
| 53 | threads = [] |
| 54 | for i in range(num_threads): |
| 55 | thread = threading.Thread(target=wrapper, args=(i,)) |
| 56 | thread.start() |
| 57 | threads.append(thread) |
| 58 | |
| 59 | for thread in threads: |
| 60 | thread.join() |
| 61 | |
| 62 | if errors: |
| 63 | # Raise only the first error |
| 64 | thread_id, error = next(iter(errors.items())) |
| 65 | error.args = (f"Error on thread {thread_id}: {error}", *error.args[1:]) |
| 66 | raise error |
| 67 | |
| 68 | return results |
| 69 | |
| 70 | |
| 71 | @params("cpu", "gpu") |
no test coverage detected