Earlier quoted context omitted.
They are async across operations that do 'yield', i.e. when the function eventually runs an i/o operation or sleep or similar. Those are the points where the functions can be interleaved. Simply awaiting another function is _not_ one of those points: await here only means the called function might yield to the scheduler at some point in its execution (it doesn't have to!), not that the calling function will yield imm…
Isn't asyncio.sleep one of those functions? "other" should be able to appear between "parent before" and "parent after".
Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
61–70 of 79 posts
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#62> Awaiting a coroutine does not give control back to the event loop. I think this is a subtler point than one might think on first read, which is muddled due to the poorly chosen examples. Here's a better illustration: import asyncio async def child(): print("child start") await asyncio.sleep(0) print("child end") async def parent(): print("parent before") await child() # It prints: other parent before child start ot…
> So the author's point is that "other" can never appear in-between "parent before" and "child start". But isn't it true for JavaScript too? So I don't really get the author's point... am I missing something or the author('s LLM?) forced a moot comparison to JavaScript? Edit: after reading the examples twice I am 99.9% sure it's slop and flagged it. Edit2: another article from the same author: https://mergify.com/blo…
I don't think so. It's been a while since I've bled on tricky async problems in either language, but I'm pretty sure in JS it would be
[...]
parent_before
parent_after
child_before
[...]
In JS, there are microtasks and macrotasks. setTimeout creates macrotasks. `.then` (and therefore `await`) creates microtasks.Microtasks get executed BEFORE macrotasks, but they still get executed AFTER the current call stack is completed.
From OP (and better illustrated by GP's example) Python's surprise is that it's just putting the awaited coroutine into the current call stack. So `await` doesn't guarantee anything is going into a task queue (micro or macro) in python.
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#63Earlier quoted context omitted.
> So the author's point is that "other" can never appear in-between "parent before" and "child start". But isn't it true for JavaScript too? So I don't really get the author's point... am I missing something or the author('s LLM?) forced a moot comparison to JavaScript? Edit: after reading the examples twice I am 99.9% sure it's slop and flagged it. Edit2: another article from the same author: https://mergify.com/blo…
> But isn't it true for JavaScript too? I don't think so. It's been a while since I've bled on tricky async problems in either language, but I'm pretty sure in JS it would be [...] parent_before parent_after child_before [...] In JS, there are microtasks and macrotasks. setTimeout creates macrotasks. `.then` (and therefore `await`) creates microtasks. Microtasks get executed BEFORE macrotasks, but they still get exec…
That doesn't make sense. That would mean the awaiting function doesn't have access to the result of the Promise (since it can proceed before the Promise is fulfilled), which would break the entire point of promises.
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#64The main takeaway for me is that in Python, this doesn't work: async def somethingLongRunning(): ... x = somethingLongRunning() ... other work that will take a lot of time ... await x # with the expectation that this will be instant if the other work was long enough That's counterintuitive coming from other languages and seems to defeat one of the key benefits of async/await (easy writing of async operations)? I've s…
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#65Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#66It's saying that the action of calling an async function (e.g. one you've written) isn't itself a yield point. The only yield points are places where we the call would block for external events like IO or time - `await asyncio.sleep(100)` would be one of those.
This is true, but surely fairly irrelevant? Any async function call has somewhere in its possible call tree one of those yield points. If it didn't then it wouldn't need to be marked async.
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#67Asynchronous and parallel programming are concepts I've never really learned, and admittedly scared to use, because I never really understand what the code is doing or even the right way of writing such code. Does anyone have any good resources that helped you learn this and have a good mental model of the concepts involved?
Write a simple single-threaded http server that takes strings and hashes them with something slow like bcrypt with a high cost value (or, just sleep before returning).
Write some integration tests (doesn’t have to be fancy) that hammer the server with 10, 100, 1000 requests.
Time how performant (or not performant) the bank of requests are.
Now try to write a threaded server where every request spins up a new thread.
What’s the performance like? (Hint: learn about the global interpreter lock (GIL))
Hmm, maybe you’re creating too many threads? Learn about thread pools and why they’re better for constraining resources.
Is performance better? Try a multiprocessing.Pool instead to defeat the GIL.
Want to try async? Do the same thing! But because the whole point of async is to do as much work on one thread with no idle time, and something like bcrypt is designed to hog the CPU, you’ll want to replace bcrypt with an await asyncio.sleep() to simulate something like a slow network request. If you wanted to use bcrypt in an async function, you’ll definitely want to delegate that work to a multiprocessing.Pool. Try that next.
Learning can be that simple. Read the docs for Thread, multiprocessing, and asyncio. Python docs are usually not very long winded and most importantly they’re more correct than some random person vibe blogging.
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#68Earlier quoted context omitted.
> So the author's point is that "other" can never appear in-between "parent before" and "child start". But isn't it true for JavaScript too? So I don't really get the author's point... am I missing something or the author('s LLM?) forced a moot comparison to JavaScript? Edit: after reading the examples twice I am 99.9% sure it's slop and flagged it. Edit2: another article from the same author: https://mergify.com/blo…
> But isn't it true for JavaScript too? I don't think so. It's been a while since I've bled on tricky async problems in either language, but I'm pretty sure in JS it would be [...] parent_before parent_after child_before [...] In JS, there are microtasks and macrotasks. setTimeout creates macrotasks. `.then` (and therefore `await`) creates microtasks. Microtasks get executed BEFORE macrotasks, but they still get exec…
Correct.
> they still get executed AFTER the current call stack is completed.
Correct.
> I'm pretty sure in JS it would be [...]
Your understanding of JS event loop is correct but you reached the wrong conclusion.
Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#69Re: Await Is Not a Context Switch: Understanding Python's Coroutines vs. Tasks
#70If this await asyncio.sleep(0) doesn't yield control back to an event loop, then what the heck is it actually for?
It does yield control. As far as I know, that's "how you're supposed to it". But the example is not great because there is no other task available to switch to, so the event loop goes right back to where it left off. While the text says otherwise, I'm pretty sure the same thing would happen in JS, C#, and Java.