6 ms·
>I am completely unconvinced by the move to asyncio everywhere in Python Me too, now. I've just been bitten by asyncio and it wasn't nice. Running many concurr
by lvass 5y ago
>I am completely unconvinced by the move to asyncio everywhere in Python
Me too, now. I've just been bitten by asyncio and it wasn't nice. Running many concurrent tasks a few of which are websockets, the state of Python websocket libraries that work with asyncio is terrible. The sockets would very silently crash until I added asyncio.sleep(0) between the more expensive CPU tasks. It's incredibly hard to debug and exceptions don't get raised properly to outside an event loop, silently making your program run in a zombie state. Even stack traces instantly become a mess when you add async. Bringing something like pandas to an environment like this is probably an immense headache.
- O5vYtytb 5y agoSounds like you need some structured concurrency. Check out Trio or AnyIO. https://trio.readthedocs.io/ https://trio.readthedocs.io/ It's too bad we got asyncio as the standard library module, though some SC concepts are going to make it into the library in future Python versions.
- nepthar 5y agoSmall plug for Kotlin as well! Yes, there's new concepts to learn with structured concurrency, but I've been mostly enjoying how quickly it gets out of your way. once properly configured :)
- vasachi 5y agoHow would Trio help with this use-case?
- O5vYtytb 5y agoStructured concurrency gives you exceptions that bubble up the stack like a normal program does, and it cancels other tasks along the way so you don't have zombies. Debugging is thusly easier as well since you keep tasks into a scope (nursery, cancel scope).
- samwillis 5y ago> The sockets would very silently crash until I added asyncio.sleep(0) between the more expensive CPU tasks. That is exactly the problem with asyncio, the minute you want to do something a little more cpu heavy it blocks. Although admittedly, you would probably see the same problem with gevent, and have to use the same sleep(0) trick. Point is for good scalability you need both traditional threads and either coroutines/asyncio to work together.
- joconde 5y ago> That is exactly the problem with asyncio, the minute you want to do something a little more cpu heavy it blocks. Isn't that by design? Sending CPU-heavy tasks to the default executor with asyncio.to_thread() works perfectly for me. Or maybe this doesn't scale in your use-case, because of the thread count limit? (Although in that case, I don't think you'd be better off without asyncio.)
- JimDabell 5y agoWon’t CPU-heavy tasks still make everything choke because of the GIL? You want to send CPU-heavy tasks to a different process instead of a different thread, don’t you?
- joconde 5y agoIn my case no, because I heavily use numpy, PyTorch, and other libraries that use C++ extensions and release the GIL during long operations. I easily use 24 CPU cores fully by submitting to one thread pool. If you use pure Python for long tasks, you're right that a ProcessPoolExecutor would be better.
- ris 5y agoIt depends what you mean by "choke". I think the parents consider "choke" to mean "will focus on one long-running task at the expense of any other task that needs to run". The GIL means that multiple threads won't be able to run python code in parallel, but the design should fairly share the available processing time between all threads that want to run.
- talideon 5y agoThe problem here is that you forgot that asyncio gives you cooperative multitasking. That means you need to hand of control periodically whenever you're doing anything CPU intensive or you end up starving everything else. That happens when you do things like an I/O operation or sleep. Either that, or you hand off the CPU intensive stuff to something on a seperate thread. Now, I'm used to this stuff from doing GUI programming on RISC OS back in the day, and got to know instinctively when I should be using WIMP_PollIdle there. For asyncio at work, I've some wrappers around range(), iter(), enumerate(), &c., that will periodically hand off control with a zero length sleep occasionally in CPU-bound code.