rsalmei / alive-progress

A new kind of Progress Bar, with real-time throughput, ETA, and very cool animations!
MIT License
5.53k stars 206 forks source link

use alive_progress with gevent, terminal only show one bar when running.but it's show all when all bar is end #95

Closed OnionTop closed 3 years ago

OnionTop commented 3 years ago
import time
import gevent
from gevent import monkey;monkey.patch_all()
from gevent.pool import Pool
from alive_progress import alive_bar
def bar(num):
    with alive_bar(total=num,bar='blocks') as bar:
        for i in range(num):
            time.sleep(0.5)
            bar()

a=[7,8,6]
pool = Pool(100)
pool.map(bar,a)
pool.join()

output result 2

rsalmei commented 3 years ago

Hey @OnionTop, thanks for your issue.

Unfortunately, this is not supported just yet. alive_progress uses Python system's sys.stdout and sys.stderr to implement the print hooks. This is needed so I can detect user code prints, and properly clean the line, print the user content, and return the bar below it.

gevent with it's light threads will try to instantiate several alive_progresses within the same Python process, which leads to the code trying to install multiple print hooks on top of each other. I don't know which Python version you are using, but on my 3.9.0 this broke with (edit: ohh, I'm using 2.0, the new super cool unreleased yet version):

2021-07-16T13:28:08Z <Greenlet at 0x109f649d0: <bound method GroupMappingMixin.__map of <Pool at 0x109998f10 set()>>(<function bar at 0x10a31b280>, [7, 8, 6])> failed with TypeError
Traceback (most recent call last):
File ".../.pyenv/versions/3.9.0/lib/python3.9/site-packages/alive_progress/core/progress.py", line 138, in start_monitoring
    hook_manager.install()
File ".../.pyenv/versions/3.9.0/lib/python3.9/site-packages/alive_progress/core/hook_manager.py", line 36, in write
    buffer = buffers[stream]
TypeError: unhashable type: 'types.SimpleNamespace'

Anyway, to get this to work, I'd have to try to disable this multiple system hook installing. Either automatically detecting it, or via a user parameter. BUT even if I did this, it would still be a mess. Each instance would try to exclusively control the terminal line, and send \r to refresh themselves at the same time. You can get a sense of what would happen with:

import time
from multiprocessing import Pool
from alive_progress import alive_bar

def bar(num):
    with alive_bar(total=num, bar='blocks') as bar:
        for i in range(num):
            time.sleep(0.5)
            bar()

if __name__ == '__main__':
    a=[7,8,6]
    with Pool(3) as pool:
        pool.map(bar,a)

Not cool. Notice how they all compete for the line (you may want to send length=10 to not wrap).

So, to get this to really work, it would need some kind of coordination between the multiple concurrent alive_progresses, in an actual multiple bars support, like in #20... It's not easy at all, but still in my radar 👍

OnionTop commented 3 years ago

Thanks for your answer,i will try your code. my python version also is 3.9