diff --git a/.meta/.readme.rst b/.meta/.readme.rst index 05509a00..3dfb34f5 100644 --- a/.meta/.readme.rst +++ b/.meta/.readme.rst @@ -476,7 +476,7 @@ Nested progress bars On Windows `colorama `__ will be used if available to keep nested bars on their respective lines. -For manual control over positioning (e.g. for multi-threaded use), +For manual control over positioning (e.g. for multi-processing use), you may specify ``position=n`` where ``n=0`` for the outermost bar, ``n=1`` for the next, and so on: @@ -484,7 +484,7 @@ you may specify ``position=n`` where ``n=0`` for the outermost bar, from time import sleep from tqdm import trange, tqdm - from multiprocessing import Pool, freeze_support, RLock + from multiprocessing import Pool, freeze_support L = list(range(9)) @@ -492,14 +492,39 @@ you may specify ``position=n`` where ``n=0`` for the outermost bar, interval = 0.001 / (n + 2) total = 5000 text = "#{}, est. {:<04.2}s".format(n, interval * total) - for i in trange(total, desc=text, position=n): + for _ in trange(total, desc=text, position=n): sleep(interval) if __name__ == '__main__': freeze_support() # for Windows support - p = Pool(len(L), initializer=tqdm.set_lock, initargs=(RLock(),)) + p = Pool(len(L), initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),)) p.map(progresser, L) +Note that in python 3, threads do not require manual positioning, +and ``tqdm.write`` is safe to use: + +.. code:: python + + from time import sleep + from tqdm import tqdm, trange + from concurrent.futures import ThreadPoolExecutor + + L = list(range(9)) + + def progresser(n): + interval = 0.001 / (n + 2) + total = 5000 + text = "#{}, est. {:<04.2}s".format(n, interval * total) + for _ in trange(total, desc=text): + sleep(interval) + if n == 6: + tqdm.write("n == 6 completed.") + tqdm.write("`tqdm.write()` is thread-safe in py3!") + + if __name__ == '__main__': + with ThreadPoolExecutor() as p: + p.map(progresser, L) + Hooks and callbacks ~~~~~~~~~~~~~~~~~~~ diff --git a/README.rst b/README.rst index 0c136e7d..9b87cdcb 100644 --- a/README.rst +++ b/README.rst @@ -640,7 +640,7 @@ Nested progress bars On Windows `colorama `__ will be used if available to keep nested bars on their respective lines. -For manual control over positioning (e.g. for multi-threaded use), +For manual control over positioning (e.g. for multi-processing use), you may specify ``position=n`` where ``n=0`` for the outermost bar, ``n=1`` for the next, and so on: @@ -648,7 +648,7 @@ you may specify ``position=n`` where ``n=0`` for the outermost bar, from time import sleep from tqdm import trange, tqdm - from multiprocessing import Pool, freeze_support, RLock + from multiprocessing import Pool, freeze_support L = list(range(9)) @@ -656,14 +656,39 @@ you may specify ``position=n`` where ``n=0`` for the outermost bar, interval = 0.001 / (n + 2) total = 5000 text = "#{}, est. {:<04.2}s".format(n, interval * total) - for i in trange(total, desc=text, position=n): + for _ in trange(total, desc=text, position=n): sleep(interval) if __name__ == '__main__': freeze_support() # for Windows support - p = Pool(len(L), initializer=tqdm.set_lock, initargs=(RLock(),)) + p = Pool(len(L), initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),)) p.map(progresser, L) +Note that in python 3, threads do not require manual positioning, +and ``tqdm.write`` is safe to use: + +.. code:: python + + from time import sleep + from tqdm import tqdm, trange + from concurrent.futures import ThreadPoolExecutor + + L = list(range(9)) + + def progresser(n): + interval = 0.001 / (n + 2) + total = 5000 + text = "#{}, est. {:<04.2}s".format(n, interval * total) + for _ in trange(total, desc=text): + sleep(interval) + if n == 6: + tqdm.write("n == 6 completed.") + tqdm.write("`tqdm.write()` is thread-safe in py3!") + + if __name__ == '__main__': + with ThreadPoolExecutor() as p: + p.map(progresser, L) + Hooks and callbacks ~~~~~~~~~~~~~~~~~~~ diff --git a/examples/parallel_bars.py b/examples/parallel_bars.py index 65a2073b..b62020a1 100644 --- a/examples/parallel_bars.py +++ b/examples/parallel_bars.py @@ -1,38 +1,50 @@ from __future__ import print_function from time import sleep from tqdm import tqdm, trange -from multiprocessing import Pool, freeze_support, RLock +from multiprocessing import Pool, freeze_support +from concurrent.futures import ThreadPoolExecutor +from functools import partial +import sys -L = list(range(9)) +L = list(range(9))[::-1] -def progresser(n): +def progresser(n, auto_position=False): interval = 0.001 / (len(L) - n + 2) total = 5000 text = "#{}, est. {:<04.2}s".format(n, interval * total) - # NB: ensure position>0 to prevent printing '\n' on completion. - # `tqdm` can't automate this since this thread - # may not know about other bars in other threads #477. - for _ in tqdm(range(total), desc=text, position=n + 1): + for _ in tqdm(range(total), desc=text, position=None if auto_position else n): sleep(interval) + # NB: may not clear instances with higher `position` upon completion + # since this worker may not know about other bars #796 + if auto_position: + # we think we know about other bars (currently only py3 threading) + if n == 6: + tqdm.write("n == 6 completed") + +if sys.version_info[:1] > (2,): + progresser_thread = partial(progresser, auto_position=True) +else: + progresser_thread = progresser if __name__ == '__main__': freeze_support() # for Windows support - p = Pool(len(L), - initializer=tqdm.set_lock, - initargs=(RLock(),)) + print("Multi-processing") + p = Pool(len(L), initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),)) p.map(progresser, L) - print('\n' * len(L)) - # alternatively, on UNIX, just use the default internal lock - p = Pool(len(L)) - p.map(progresser, L) - print('\n' * len(L)) + # unfortunately need ncols + # to print spaces over leftover multi-processing bars (#796) + with tqdm(leave=False) as t: + ncols = t.ncols or 80 + print(("{msg:<{ncols}}").format(msg="Multi-threading", ncols=ncols)) - # a manual test demonstrating automatic fix for #477 on one thread - for _ in trange(10, desc="1", position=1): - for _ in trange(10, desc="2", position=0): + with ThreadPoolExecutor(4) as p: + p.map(progresser_thread, L) + + print("Manual nesting") + for i in trange(16, desc="1"): + for _ in trange(16, desc="2 @ %d" % i, leave=i % 2): sleep(0.01) - print('\n')