61

From the perspective of someone who has written asyncio code but is looking to better understand the inner workings, what is yield from, await and how are those useful for allowing asynchronous code?

There is one highly upvoted question asking about the uses of the yield from syntax and one explaining async and await, but both go in depth about different topics and are not really a concise explanation of the underlying code and how it fits in with asyncio.

Azsgy
  • 3,139
  • 2
  • 29
  • 40
  • It seems like the second question that you've linked gives a pretty straight forward explanation of how `async` and `await` can be used to more succinctly express what you used to need `yield from` & `asyncio.coroutine` to express. I guess I'm not really sure what the question is asking since that example seems to explain it pretty well. Can you be more specific? – mgilson May 29 '17 at 22:53
  • @mgilson it goes into how `await` relates to `yield from` but not actually what `yield from` does – Azsgy May 29 '17 at 22:55
  • 1
    They're the same, except `await` is more [recent](https://www.python.org/dev/peps/pep-0492/) and looks much better – Vincent May 30 '17 at 16:40

1 Answers1

86

Short answer:

yield from is an old way to wait for asyncio's coroutine.

await is a modern way to wait for asyncio's coroutine.

Detailed answer:

Python has generators - special kind of functions that produces a sequence of results instead of a single value. Starting with Python 3.3 yield from expression was added. It allows one generator to delegate part of its operations to another generator.

Starting with Python 3.4 asyncio module was added to standard library. It allow us to write clear and understandable asynchronous code. While technically asyncio's coroutines could be implemented different ways, in asyncio they were implemented using generators (you can watch for excellent video where shown how generators can be used to implement coroutines). @asyncio.coroutine was a way to make coroutine from generator and yield from was a way to await for coroutine - just details of implementation.

That's how happened that yield from started to be used for two "different things".

Starting with Python 3.5 (see PEP 492) coroutines got new syntax. Now you can define coroutine with async def and await for it using await expression. It's not only shorter to write, but also makes clearer to understand that we work with asyncio's coroutines.

If you're using Python 3.5+ you can forget about using yield from for asyncio's coroutines and use await for it.

Mikhail Gerasimov
  • 36,989
  • 16
  • 116
  • 159
  • 2
    Holy c**p, @mikhail, I wish I had read this before wasting so much of my time with `yield from` and `@asyncio.coroutine`! Then I read `async def` and `await`, and I went "ummmm, I wonder what's the difference". I wish this were made clearer in [PEP 3156](https://www.python.org/dev/peps/pep-3156)... – Marco Massenzio Feb 20 '18 at 01:26
  • 1
    Thanks. "except generators" should maybe be a little more explicit, you are technically correct that an instance of `def foo(): x = yield` is of type `generator` (for historic reasons), but colloquially it's a "[Beazly-style](http://www.dabeaz.com/coroutines/)" coroutine and not really what people think of when saying generator. – timgeb Sep 10 '18 at 15:00
  • 1
    @timgeb thanks, corrected. I think now should be ok :) – Mikhail Gerasimov Sep 10 '18 at 15:10
  • I personally think this is the most confusing questions/documents in whole Python history. With "async def" and "await", it gets 10x better but still, it's the most confusing feature for Python. I don't get how they even make "yield from" officiallly released... If I were to learn a new language now, I would skip Python just because of this syntax. – user2189731 Feb 27 '19 at 05:44
  • I understand that `await` actually allows Python to do other stuff while the awaited task is in progress. Is this the case with `yield from` as well? It feels like `yield from` is blocking (presumably because it's just a chain of `yield`s) – Jay Jun 19 '20 at 08:11
  • 3
    @Jay `await` (as well as its old version `yield from`) will "block" local execution flow without blocking event loop. To run task without blocking local execution flow, you need to create asyncio's task - [read about it here](https://stackoverflow.com/a/37345564/1113207). – Mikhail Gerasimov Jun 19 '20 at 08:19