0

Does asyncio execute other waiting "awaitables" only when it encounters waiting in the current awaitable?

I'm trying to grasp the concept of asyncio and coroutines. I've played a bit with greenlets/gevent before and I know there was switching of context. The code was synchronous, but the context switched and something else was executed when programmer manually called switch().

Because of GIL, if multiprocessing is not involved, there is no parallelism at all. The code may switch context to give an impression of parallelism, but nothing more.

If I understand threading correctly, the context switching occurs regularly.

If A is one task and B is another, the execution can be visualised as ABABABABABABABABABAB. I'm not sure how the thread is split to these smaller parts, how many interpreter instructions or I dont know, processor operations, they contain, or how much time does a single part take. So please light me up.

But when it comes to asyncio or coroutines, people say that its good for IO because it can do stuff during "waiting" time. So the execution could be visualized as:

AAAAAAABBBBAAA
       |   |  
       |   B called .wait() so switching to A
       A called .wait() so switching to B

So if there is a loop to check if there is a new message in the socket:

# pseudocode, the normal code would use select() and sock.recv()
while not (data := sock.receive_nowait()):
    asyncio.sleep(0.001)

Then this waiting time can be utilized to do some other stuff. But... will this "other stuff" take only 0.001s? Or will it stop only if it encounters .sleep() in other coroutine?

I'm probably messing all this up, but I hope you'll help me understand that.

majkelpl
  • 25
  • 3
  • 1
    With async one is explicit about when control is given up and when it is passed. In general a coroutine must be awaited by another coroutine in order to run. This is similar to how a generator function (with a `yield`) does not run except when being iterated over. Of course with aysync one must choose one of the various ways to trigger a coroutine from regular program flow (instead of from another coroutine) or else none of them will actually run. Once actually run a coroutine will pass control when it awaits another coroutine. – Andrew Allaire Mar 21 '22 at 19:36
  • **Okay after some digging and organizing stuff in my head, I feel that I understand it better.** What I wrote in the post is true: coroutines are cooperative multitasking, so manual switching is necessary, while threads are preemptive multitasking, so a scheduler is responsible for allowing threads to run. Asyncio is better for slow-IO code because it wont switch to a waiting thread which could happen in threading, plus less resources are necessary. – majkelpl Mar 22 '22 at 06:20
  • Does this answer your question? [How does asyncio actually work?](https://stackoverflow.com/questions/49005651/how-does-asyncio-actually-work) – MisterMiyagi Mar 22 '22 at 07:49
  • 1
    Coroutines are the same basic idea as threads, but implemented differently. – user253751 Mar 22 '22 at 13:23

0 Answers0