Hacker News new | ask | show | jobs
by scribu 209 days 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

3 comments

Thank you!! The examples in the post illustrated nothing, it was driving me crazy.
Yes, the examples were sloppy.
> 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-...

> 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.

> 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
> 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.

>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.

> 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.

Yep, 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.

Doesn't this make await a no-op? In what way are async functions asynchronous if tasks do not run interleaved?
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 immediately.
Isn't asyncio.sleep one of those functions? "other" should be able to appear between "parent before" and "parent after".
Yes, but not between "parent before" and "child start" (or between "child end" and "parent after")
Ah, OK. That makes sense.
Tasks 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.