rsalmei / alive-progress

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

Can this be used with async libraries? #227

Closed Tosh0kan closed 1 year ago

Tosh0kan commented 1 year ago

I'm trying to figure out how to use Alive Progress with httpx, which is a requests libraries that can do multiple requests asynchronously. I can use just fine when it's just one connection or multiple connections done synchronously, but I'm struggling how to use this with multiple, asynchronous connections. Is it possible?

rsalmei commented 1 year ago

Yes, that should be possible, there's nothing inherently inappropriate in using async with alive-progress. Why are you struggling, what happens? You can find some example codes here on past issues.

Tosh0kan commented 1 year ago

Yeah, I know. In fact, it was thanks to your snippet on issue #218 that led me to actually grasp the concept. What I'm having issues with is specifically how to access the multiple streams all at once.

From my understanding, with an asynchronous requests library, the server will receive multiple requests at once, and will download multiple things in parallel through the await asyncio.gather(*tasks). I have no idea how to get into that coroutine to use the total = int(response.headers["Content-Length"]) on each of the urls of tasks them sum all of them use that as the total for alive-bar.

Also, saudações do Rio!

rsalmei commented 1 year ago

Ohh, vc é do Rio? Sou de SP, saudações 😉

Anyway, there are better async examples here, just look for issues about asyncio or executors, especially the closed ones.

But no, asynchronous is NOTHING about parallel things, it is about concurrent things, which is very different. An async task will run on an async engine unhindered until it has to stop because of some pending IO operation, i.e. when it has to await for external things. This makes it completely stop and another task, which can already make progress because its IO is ready, comes back and gets to run again. That's why you should never do CPU-bound operations on an async task, because it will make all other concurrent tasks stop working. Well, if you do still have any specific doubts, please provide an example code so I can help you make it work.

Inté!! 😜

rsalmei commented 1 year ago

Hey @Tosh0kan, any news here? Would you have some code so I can see what you are struggling with?

Tosh0kan commented 1 year ago

@rsalmei Oh, don't worry about it. The code I wanted to include this turned out to be unnecessary, since there was already a program that did what I wanted to do with it, and also because of IRL situations, I haven't been able to mess around with this lib. Sorry that I forgot to close the issue. Thank you for the care 😄

rsalmei commented 1 year ago

No problem 😉

j-ntw commented 1 year ago

hey @rsalmei , im using python 3.11 and 3.1.4 of alive-progress.

It seems either asyncio taskgroups or asyncio.gather triggers "UserWarning: Nested use of alive_progress is not yet supported."

from alive_progress import alive_bar
import asyncio

# dummy function
async def instance():
    with alive_bar(title="self", bar =None, spinner ="waves", stats =None, elapsed = "{elapsed}", monitor=None) as bar:
        # simulate some IO functions
        await asyncio.sleep(1)
        bar.title = "self2"
        await asyncio.sleep(1)

# driver
async def amain():
    # await asyncio.gather(instance(), instance())
    async with asyncio.TaskGroup() as tg:
        tg.create_task(instance())
        tg.create_task(instance())

if __name__ == "__main__":
    asyncio.run(amain())

Do you have any advice on how to proceed?

rsalmei commented 1 year ago

Yep, alive_bar can not be used on the task itself, ever. The async loop will end up starting more than one task at the same time, and trigger a nested use...

The correct way would be to use alive_bar on a common center point like main() which starts tasks, then be notified somehow that tasks are being completed, like with asyncio.gather() or using queues. I have some examples in closed tickets if you'd like to.

j-ntw commented 1 year ago

Thanks for the speedy reply. I need multiple spinners for concurrent tasks, if you have examples that would work great.

By the way, perhaps there could be an FAQ or Github Discussions page for async related questions since i see people have had related questions.

rsalmei commented 1 year ago

You're welcome. There's no support for multiple bars concurrently on screen. It is very complicated to manage a single cursor amongst several bars with different refresh rates, so I haven't tried it yet. Good idea, I surely can open a discussion for that.

allrobot commented 4 months ago

You're welcome. There's no support for multiple bars concurrently on screen. It is very complicated to manage a single cursor amongst several bars with different refresh rates, so I haven't tried it yet. Good idea, I surely can open a discussion for that.

Hello

  1. Can you support real-time refreshing output for multiple progress bars in asynchronous scenario? For example, the first line, second line, or x line display the progress bars and update them in real-time.

  2. Your alive-progress is way cooler than tqdm, but it seems like it doesn't support asynchronous output? Could it be made to have APIs similar to tqdm_asyncio.as_completed, asyncio.as_completed, or tqdm_asyncio.gather? https://github.com/tqdm/tqdm

tqdm support asynchronous. I hope your project can do it