4 ms·
> 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 t
by scribu 10mo ago
> 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() # <-- awaiting a coroutine (not a task)
print("parent after")
async def other():
for _ in range(5):
print("other")
await asyncio.sleep(0)
async def main():
other_task = asyncio.create_task(other())
parent_task = asyncio.create_task(parent())
await asyncio.gather(other_task, parent_task)
asyncio.run(main())
It prints:
other
parent before
child start
other
child end
parent after
other
other
other
So the author's point is that "other" can never appear in-between "parent before" and "child start".
Edit: clarification
- raincole 10mo ago> 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/blog/why-warning-has-no-place-in-modern-logging https://mergify.com/blog/why-warning-has-no-place-in-modern-... > This isn’t just text — it’s structured, filterable, and actionable. My conclusion is that I should ask LLM to write a browser userscript to automatically flag and hide links from this domain for me.
- scribu 10mo ago> But isn't it true for JavaScript too? You're right, the equivalent JS script produces the same sequence of outputs. It turns out there is a way to emulate Python's asyncio.create_task(). Python: await asyncio.create_task(child()) JavaScript: const childTask = new Promise((resolve) => { setTimeout(() => child().then(resolve), 0) }) await childTask
- furyofantares 10mo agoYep, it's another slop. We are getting these about daily now where there's lots of comments on articles that'd are clearly slop. Half the article is paragraph headings, the other half is bullet points or numbered lists, if there was anything interesting in the prompt it'd been erased by an LLM which has turned it into an infodump with no perspective, nothing to convey, and I have no ability to tell what if anything might have been important to the author (besides blog clicks and maybe the title). I really wish we could start recognizing these sooner, I think too many people skim and then go to the comments section but I don't think we really want HN to be a place filled with low value articles just because they're good jumping off points for comments. I've been flagging them here and then heading over to kagi and marking as slop there. Makes me wish we had something similar here rather than just "flag". And I know we aren't supposed to comment when we flag, but this feels different to me, like we've got to collectively learn to notice this better or we need better tools.
- rjmill 10mo ago> 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 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.
- fluoridation 10mo ago>I'm pretty sure in JS it would be [...] 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.
- raincole 10mo ago> Microtasks get executed BEFORE macrotasks 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.
- titanomachy 10mo agoThank you!! The examples in the post illustrated nothing, it was driving me crazy.
- cuu508 10mo agoYes, the examples were sloppy.
- fluoridation 10mo agoDoesn't this make await a no-op? In what way are async functions asynchronous if tasks do not run interleaved?
- throwup238 10mo agoTasks are async funcs that have been spawned with asyncio.create_task or similar, which then schedules its execution. A timer of zero doesn't spawn anything so the coroutine just executes in the same frame as the caller so yes it essentially a noop.
- rcxdude 10mo agoThey 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 immediately.
- fluoridation 10mo agoIsn't asyncio.sleep one of those functions? "other" should be able to appear between "parent before" and "parent after".
- rcxdude 10mo agoYes, but not between "parent before" and "child start" (or between "child end" and "parent after")
- fluoridation 10mo agoAh, OK. That makes sense.