5

Is there a way to create a task but to have it specifically the next task run in the event loop?

Suppose I have an event loop currently running several low priority coroutines. Perhaps a few high priority API request tasks come along and I want to immediately asynchronously make these requests and then yield control back to the tasks previously in the loop.

I realize that the latency with a network request is orders of magnitude larger than a few CPU cycles saved by reordering the cooperative tasks in the loop, but nevertheless I am curious if there is a way to achieve this.

1 Answer 1

3

I want to immediately asynchronously make these requests and then yield control back to the tasks previously in the loop.

There is no way to do that in the current asyncio, where all runnable tasks reside in a non-prioritized queue.

But there is a deeper issue with the above requirement. Asynchronous tasks potentially yield control to the event loop at every blocking IO call, or more generally at every await. So "immediately" and "asynchronously" don't go together: a truly asynchronous operation cannot be immediate because it has to be suspendable, and when it is suspended, other tasks will proceed.

If you really want something to happen immediately, you need to do it synchronously. Other tasks will be blocked anyway because the synchronous operation will not allow them to run.

This is likely the reason why asyncio doesn't support task prioritization. By their very nature tasks execute in short slices that can be interleaved in arbitrary ways, so the order in which they execute should not matter in general. In cases when the order does matter, one is expected to use the provided synchronization devices.

Sign up to request clarification or add additional context in comments.

3 Comments

In response to your comment about the apparent contradiction between wanting a task to happen asynchronously as well as immediately, in my case there may be an urgent API request, for example to cancel a trade. It is desirable to send the http request asap. The confirmation response form the exchange is of lower priority than other existing tasks in the event loop, so yielding after the http request is sent is absolutely fine. The ability to force a new task to the front of the event loop would be beneficial in this situation.
@JSStuball Asyncio is designed so that (barring a bug) nothing blocks anything else. Everything done inside the event loop is either a non-blocking IO call or a brief preparation for it - anything else is done in separate threads. So, you could simply issue your urgent http request using asyncio.create_task(urgent(...)) and it would be executed concurrently with all other tasks, certainly without being blocked by any of them. Note that the request could be sent a microsecond after some other request because the other happened to be queued sooner, but asyncio is not a real-time system.
Having said that, if I really needed to fire an out-of-band urgent request, I would use synchronous code from a separate thread (possibly pre-spawned for efficiency). That provides probably the optimal efficiency you can get in Python without complicating the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.