A bunch of threads.
| 26 | |
| 27 | |
| 28 | class Bunch(object): |
| 29 | """ |
| 30 | A bunch of threads. |
| 31 | """ |
| 32 | def __init__(self, func, nthread, wait_before_exit=False): |
| 33 | """ |
| 34 | Construct a bunch of `nthread` threads running the same function `func`. |
| 35 | If `wait_before_exit` is True, the threads won't terminate until |
| 36 | do_finish() is called. |
| 37 | """ |
| 38 | self.func = func |
| 39 | self.nthread = nthread |
| 40 | self.started = [] |
| 41 | self.finished = [] |
| 42 | self.exceptions = [] |
| 43 | self._can_exit = not wait_before_exit |
| 44 | self._wait_thread = None |
| 45 | |
| 46 | def task(self): |
| 47 | tid = threading.get_ident() |
| 48 | self.started.append(tid) |
| 49 | try: |
| 50 | self.func() |
| 51 | except BaseException as exc: |
| 52 | self.exceptions.append(exc) |
| 53 | finally: |
| 54 | self.finished.append(tid) |
| 55 | for _ in support.sleeping_retry(support.SHORT_TIMEOUT): |
| 56 | if self._can_exit: |
| 57 | break |
| 58 | |
| 59 | def __enter__(self): |
| 60 | self._wait_thread = threading_helper.wait_threads_exit(support.SHORT_TIMEOUT) |
| 61 | self._wait_thread.__enter__() |
| 62 | |
| 63 | try: |
| 64 | for _ in range(self.nthread): |
| 65 | start_new_thread(self.task, ()) |
| 66 | except: |
| 67 | self._can_exit = True |
| 68 | raise |
| 69 | |
| 70 | for _ in support.sleeping_retry(support.SHORT_TIMEOUT): |
| 71 | if len(self.started) >= self.nthread: |
| 72 | break |
| 73 | |
| 74 | return self |
| 75 | |
| 76 | def __exit__(self, exc_type, exc_value, traceback): |
| 77 | for _ in support.sleeping_retry(support.SHORT_TIMEOUT): |
| 78 | if len(self.finished) >= self.nthread: |
| 79 | break |
| 80 | |
| 81 | # Wait until threads completely exit according to _thread._count() |
| 82 | self._wait_thread.__exit__(None, None, None) |
| 83 | |
| 84 | # Break reference cycle |
| 85 | exceptions = self.exceptions |
no outgoing calls
searching dependent graphs…