Provide a default write lock for thread and multiprocessing safety. Works only on platforms supporting `fork` (so Windows is excluded). You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance before forking in order for the write lock to work. On Windows, you need to sup
| 74 | |
| 75 | |
| 76 | class TqdmDefaultWriteLock: |
| 77 | """ |
| 78 | Provide a default write lock for thread and multiprocessing safety. |
| 79 | Works only on platforms supporting `fork` (so Windows is excluded). |
| 80 | You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance |
| 81 | before forking in order for the write lock to work. |
| 82 | On Windows, you need to supply the lock from the parent to the children as |
| 83 | an argument to joblib or the parallelism lib you use. |
| 84 | """ |
| 85 | # global thread lock so no setup required for multithreading. |
| 86 | # NB: Do not create multiprocessing lock as it sets the multiprocessing |
| 87 | # context, disallowing `spawn()`/`forkserver()` |
| 88 | th_lock = TRLock() |
| 89 | |
| 90 | def __init__(self): |
| 91 | # Create global parallelism locks to avoid racing issues with parallel |
| 92 | # bars works only if fork available (Linux/MacOSX, but not Windows) |
| 93 | cls = type(self) |
| 94 | root_lock = cls.th_lock |
| 95 | if root_lock is not None: |
| 96 | root_lock.acquire() |
| 97 | cls.create_mp_lock() |
| 98 | self.locks = [lk for lk in [cls.mp_lock, cls.th_lock] if lk is not None] |
| 99 | if root_lock is not None: |
| 100 | root_lock.release() |
| 101 | |
| 102 | def acquire(self, *a, **k): |
| 103 | for lock in self.locks: |
| 104 | lock.acquire(*a, **k) |
| 105 | |
| 106 | def release(self): |
| 107 | for lock in self.locks[::-1]: # Release in inverse order of acquisition |
| 108 | lock.release() |
| 109 | |
| 110 | def __enter__(self): |
| 111 | self.acquire() |
| 112 | |
| 113 | def __exit__(self, *exc): |
| 114 | self.release() |
| 115 | |
| 116 | @classmethod |
| 117 | def create_mp_lock(cls): |
| 118 | if not hasattr(cls, 'mp_lock'): |
| 119 | try: |
| 120 | from multiprocessing import RLock |
| 121 | cls.mp_lock = RLock() |
| 122 | except (ImportError, OSError): # pragma: no cover |
| 123 | cls.mp_lock = None |
| 124 | |
| 125 | @classmethod |
| 126 | def create_th_lock(cls): |
| 127 | assert hasattr(cls, 'th_lock') |
| 128 | warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2) |
| 129 | |
| 130 | |
| 131 | class Bar: |