Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Goroutines vs asyncio tasks + thread pool for CPU-bound calls

Are goroutines roughly equivalent to python's asyncio tasks, with an additional feature that any CPU-bound task is routed to a ThreadPoolExecutor instead of being added to the event loop (of course, with the assumption that we use a python interpreter without GIL)?

Is there any substantial difference between the two approaches that I'm missing? Of course, apart from the efficiencies and code clarity that result from the concurrency being an integral part of Go.

like image 616
max Avatar asked May 30 '17 22:05

max


People also ask

Why is Asyncio better than threading?

One of the cool advantages of asyncio is that it scales far better than threading . Each task takes far fewer resources and less time to create than a thread, so creating and running more of them works well. This example just creates a separate task for each site to download, which works out quite well.

Does Asyncio use multiple cores?

asyncio, coroutines, greenlets, etc. have no direct effect on performance and do not help using multiple cores efficiently; asynchronous systems may lead to slower performance (ex.

Is Python Asyncio multithreaded?

In Python, asyncio module provides this capability. Multiple tasks can run concurrently on a single thread, which is scheduled on a single CPU core. Although Python supports multithreading, concurrency is limited by the Global Interpreter Lock ( GIL ).


1 Answers

I think I know part of the answer. I tried to summarize my understanding of the differences, in order of importance, between asyncio tasks and goroutines:

1) Unlike under asyncio, one rarely needs to worry that their goroutine will block for too long. OTOH, memory sharing across goroutines is akin to memory sharing across threads rather than asyncio tasks since goroutine execution order guarantees are much weaker (even if the hardware has only a single core).

asyncio will only switch context on explicit await, yield and certain event loop methods, while Go runtime may switch on far more subtle triggers (such as certain function calls). So asyncio is perfectly cooperative, while goroutines are only mostly cooperative (and the roadmap suggests they will become even less cooperative over time).

A really tight loop (such as with numeric computation) could still block Go runtime (well, the thread it's running on). If it happens, it's going to have less of an impact than in python - unless it occurs in mutliple threads.

2) Goroutines are have off-the-shelf support for parallel computation, which would require a more sophisticated approach under asyncio.

Go runtime can run threads in parallel (if multiple cores are available), and so it's somewhat similar to running multiple asyncio event loops in a thread pool under a GIL-less python runtime, with a language-aware load balancer in front.

3) Go runtime will automatically handle blocking syscalls in a separate thread; this needs to be done explicitly under asyncio (e.g., using run_in_executor).

That said, in terms of memory cost, goroutines are very much like asyncio tasks rather than threads.

like image 89
max Avatar answered Nov 15 '22 08:11

max