No, co-routines do not involve any kind of threads. Co-routines allow for cooperative multi-tasking in that each co-routine yields control voluntarily. Threads on the other hand switch between units at arbitrary points.
Up to Python 3.4, it was possible to write co-routines using generators; by using yield
or yield from
expressions in a function body you create a generator object instead, where code is only executed when you iterate over the generator. Together with additional event loop libraries (such as asyncio
) you could write co-routines that would signal to an event loop that they were going to be busy (waiting for I/O perhaps) and that another co-routine could be run in the meantime:
import asyncio
import datetime
@asyncio.coroutine
def display_date(loop):
end_time = loop.time() + 5.0
while True:
print(datetime.datetime.now())
if (loop.time() + 1.0) >= end_time:
break
yield from asyncio.sleep(1)
Every time the above code advances to the yield from asyncio.sleep(1)
line, the event loop is free to run a different co-routine, because this routine is not going to do anything for the next second anyway.
Because generators can be used for all sorts of tasks, not just co-routines, and because writing a co-routine using generator syntax can be confusing to new-comers, the PEP introduces new syntax that makes it clearer that you are writing a co-routine.
With the PEP implemented, the above sample could be written instead as:
async def display_date(loop):
end_time = loop.time() + 5.0
while True:
print(datetime.datetime.now())
if (loop.time() + 1.0) >= end_time:
break
await asyncio.sleep(1)
The resulting coroutine
object still needs an event loop to drive the co-routines; an event loop would await
on each co-routine in turn, which would execute those co-routines that are not currently await
ing for something to complete.
The advantages are that with native support, you can also introduce additional syntax to support asynchronous context managers and iterators. Entering and exiting a context manager, or looping over an iterator then can become more points in your co-routine that signal that other code can run instead because something is waiting again.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…