How does python co-program asyncio schedule the co-program?

in the past, I used to put future directly into eventloop to perform run_until_complete, interview. When an interviewer asked me how to schedule the program, I was completely confused. May I ask how you are dispatched?


Chinese dictionary interpretation, scheduling for management and arrangement. For a coroutine, schedule, it's not just run_until_complete -- it's just arranged to start a coroutine immediately and wait until it's complete; during the execution of the coroutine, you don't manage or schedule the details of the coroutine yourself. What the interviewer wants you to answer is how event loop will schedule coroutine after it takes over.

for Python, coroutine in a narrow sense refers to an instance of coroutine , which is usually the return value of calling a async def function, for example:

  priority queue   _ scheduled  in 
  • goes back to main () , where await returns the Future instance that slept for 1 second to the previous send () call;
  • Task._step () finds that an instance of Future has been received, and immediately calls its add_done_callback () to register the steps to be continued in the future.
  • go back to the main event loop loop and continue to execute loop._run_once () ;
  • next time.
  • this time the _ ready queue is empty, but there is something in the _ scheduled priority queue. Event loop will check whether the recently planned TimerHandle is due to be executed-obviously we have just scheduled it for a second before execution, so we will not execute immediately, but calculate how long we should wait before execution (it will be slightly shorter than 1 second because other code has been run after the schedule);
  • calls selector.select () and takes the above time as the timeout parameter. The call blocks for nearly 1 second because no other Iamp O events are registered;
  • execute loop._run_once () for the third time, and find a TimerHandle is due, execute it immediately;
  • flip through the previous steps. This TimerHandle will call sleep to generate Future instance set_result () ;
  • .
  • once the Future instance has a result, it will then trigger the execution of the previously registered done callback, that is, resume the execution of Task .
  • in the new Task._step () call, Task will call coro.send () again to finish executing the remaining return 123 in main () .
  • the result returned here 123 will be used by Task to call self.set_result . After all, Task is the earliest Future instance;
  • looking back at step 3, this Future instance has been added by run_until_complete with a done callback, function to stop event loop. So, at this point, event loop will be set to be stopped;
  • The execution of TimerHandle is completed and enters the next main loop, but because event loop has been set to be stopped, the main loop ends because the condition is not met. loop.run_forever () is returned.
  • goes back to the original run_until_complete () , which returns future.result () , that is, 123 , and finally assigns a value to rv .
  • to sum up, event loop's scheduling of callback is preemptive: _ scheduled if there is a time in the priority queue, the first-come-first-served callback will be executed first, and then the callback will be executed on a first-come-first-served basis, and all the callbacks will be executed as long as there is a callback in the _ ready queue, so as to repeat until someone actively stops event loop. Finally, a coroutine is executed by multiple callbacks driven by Task , and the split point is await ; for multiple concurrent coroutine, macroscopically, the scheduling method is "who executes a segment first when the time is up, or who executes a segment first when there is progress in the Icode O event, or who registers first".

    Menu