mirror of https://github.com/python/cpython.git
bpo-32258: Replace 'yield from' to 'await' in asyncio docs (#4779)
* Replace 'yield from' to 'await' in asyncio docs * Fix docstrings
This commit is contained in:
parent
abae67ebc2
commit
8874342cf3
|
@ -81,12 +81,11 @@ is called.
|
|||
If you wait for a future, you should check early if the future was cancelled to
|
||||
avoid useless operations. Example::
|
||||
|
||||
@coroutine
|
||||
def slow_operation(fut):
|
||||
async def slow_operation(fut):
|
||||
if fut.cancelled():
|
||||
return
|
||||
# ... slow computation ...
|
||||
yield from fut
|
||||
await fut
|
||||
# ...
|
||||
|
||||
The :func:`shield` function can also be used to ignore cancellation.
|
||||
|
@ -99,7 +98,7 @@ Concurrency and multithreading
|
|||
|
||||
An event loop runs in a thread and executes all callbacks and tasks in the same
|
||||
thread. While a task is running in the event loop, no other task is running in
|
||||
the same thread. But when the task uses ``yield from``, the task is suspended
|
||||
the same thread. But when the task uses ``await``, the task is suspended
|
||||
and the event loop executes the next task.
|
||||
|
||||
To schedule a callback from a different thread, the
|
||||
|
@ -192,8 +191,7 @@ Example with the bug::
|
|||
|
||||
import asyncio
|
||||
|
||||
@asyncio.coroutine
|
||||
def test():
|
||||
async def test():
|
||||
print("never scheduled")
|
||||
|
||||
test()
|
||||
|
@ -270,10 +268,9 @@ traceback where the task was created. Output in debug mode::
|
|||
There are different options to fix this issue. The first option is to chain the
|
||||
coroutine in another coroutine and use classic try/except::
|
||||
|
||||
@asyncio.coroutine
|
||||
def handle_exception():
|
||||
async def handle_exception():
|
||||
try:
|
||||
yield from bug()
|
||||
await bug()
|
||||
except Exception:
|
||||
print("exception consumed")
|
||||
|
||||
|
@ -300,7 +297,7 @@ Chain coroutines correctly
|
|||
--------------------------
|
||||
|
||||
When a coroutine function calls other coroutine functions and tasks, they
|
||||
should be chained explicitly with ``yield from``. Otherwise, the execution is
|
||||
should be chained explicitly with ``await``. Otherwise, the execution is
|
||||
not guaranteed to be sequential.
|
||||
|
||||
Example with different bugs using :func:`asyncio.sleep` to simulate slow
|
||||
|
@ -308,26 +305,22 @@ operations::
|
|||
|
||||
import asyncio
|
||||
|
||||
@asyncio.coroutine
|
||||
def create():
|
||||
yield from asyncio.sleep(3.0)
|
||||
async def create():
|
||||
await asyncio.sleep(3.0)
|
||||
print("(1) create file")
|
||||
|
||||
@asyncio.coroutine
|
||||
def write():
|
||||
yield from asyncio.sleep(1.0)
|
||||
async def write():
|
||||
await asyncio.sleep(1.0)
|
||||
print("(2) write into file")
|
||||
|
||||
@asyncio.coroutine
|
||||
def close():
|
||||
async def close():
|
||||
print("(3) close file")
|
||||
|
||||
@asyncio.coroutine
|
||||
def test():
|
||||
async def test():
|
||||
asyncio.ensure_future(create())
|
||||
asyncio.ensure_future(write())
|
||||
asyncio.ensure_future(close())
|
||||
yield from asyncio.sleep(2.0)
|
||||
await asyncio.sleep(2.0)
|
||||
loop.stop()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
@ -359,24 +352,22 @@ The loop stopped before the ``create()`` finished, ``close()`` has been called
|
|||
before ``write()``, whereas coroutine functions were called in this order:
|
||||
``create()``, ``write()``, ``close()``.
|
||||
|
||||
To fix the example, tasks must be marked with ``yield from``::
|
||||
To fix the example, tasks must be marked with ``await``::
|
||||
|
||||
@asyncio.coroutine
|
||||
def test():
|
||||
yield from asyncio.ensure_future(create())
|
||||
yield from asyncio.ensure_future(write())
|
||||
yield from asyncio.ensure_future(close())
|
||||
yield from asyncio.sleep(2.0)
|
||||
async def test():
|
||||
await asyncio.ensure_future(create())
|
||||
await asyncio.ensure_future(write())
|
||||
await asyncio.ensure_future(close())
|
||||
await asyncio.sleep(2.0)
|
||||
loop.stop()
|
||||
|
||||
Or without ``asyncio.ensure_future()``::
|
||||
|
||||
@asyncio.coroutine
|
||||
def test():
|
||||
yield from create()
|
||||
yield from write()
|
||||
yield from close()
|
||||
yield from asyncio.sleep(2.0)
|
||||
async def test():
|
||||
await create()
|
||||
await write()
|
||||
await close()
|
||||
await asyncio.sleep(2.0)
|
||||
loop.stop()
|
||||
|
||||
|
||||
|
|
|
@ -488,8 +488,9 @@ Coroutines can be scheduled in a protocol method using :func:`ensure_future`,
|
|||
but there is no guarantee made about the execution order. Protocols are not
|
||||
aware of coroutines created in protocol methods and so will not wait for them.
|
||||
|
||||
To have a reliable execution order, use :ref:`stream objects <asyncio-streams>` in a
|
||||
coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain`
|
||||
To have a reliable execution order,
|
||||
use :ref:`stream objects <asyncio-streams>` in a
|
||||
coroutine with ``await``. For example, the :meth:`StreamWriter.drain`
|
||||
coroutine can be used to wait until the write buffer is flushed.
|
||||
|
||||
|
||||
|
@ -589,7 +590,7 @@ received data and close the connection::
|
|||
|
||||
:meth:`Transport.close` can be called immediately after
|
||||
:meth:`WriteTransport.write` even if data are not sent yet on the socket: both
|
||||
methods are asynchronous. ``yield from`` is not needed because these transport
|
||||
methods are asynchronous. ``await`` is not needed because these transport
|
||||
methods are not coroutines.
|
||||
|
||||
.. seealso::
|
||||
|
|
|
@ -24,7 +24,7 @@ Queue
|
|||
A queue, useful for coordinating producer and consumer coroutines.
|
||||
|
||||
If *maxsize* is less than or equal to zero, the queue size is infinite. If
|
||||
it is an integer greater than ``0``, then ``yield from put()`` will block
|
||||
it is an integer greater than ``0``, then ``await put()`` will block
|
||||
when the queue reaches *maxsize*, until an item is removed by :meth:`get`.
|
||||
|
||||
Unlike the standard library :mod:`queue`, you can reliably know this Queue's
|
||||
|
|
|
@ -208,7 +208,7 @@ StreamWriter
|
|||
The intended use is to write::
|
||||
|
||||
w.write(data)
|
||||
yield from w.drain()
|
||||
await w.drain()
|
||||
|
||||
When the size of the transport buffer reaches the high-water limit (the
|
||||
protocol is paused), block until the size of the buffer is drained down
|
||||
|
@ -301,15 +301,14 @@ TCP echo client using the :func:`asyncio.open_connection` function::
|
|||
|
||||
import asyncio
|
||||
|
||||
@asyncio.coroutine
|
||||
def tcp_echo_client(message, loop):
|
||||
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,
|
||||
loop=loop)
|
||||
async def tcp_echo_client(message, loop):
|
||||
reader, writer = await asyncio.open_connection('127.0.0.1', 8888,
|
||||
loop=loop)
|
||||
|
||||
print('Send: %r' % message)
|
||||
writer.write(message.encode())
|
||||
|
||||
data = yield from reader.read(100)
|
||||
data = await reader.read(100)
|
||||
print('Received: %r' % data.decode())
|
||||
|
||||
print('Close the socket')
|
||||
|
@ -335,16 +334,15 @@ TCP echo server using the :func:`asyncio.start_server` function::
|
|||
|
||||
import asyncio
|
||||
|
||||
@asyncio.coroutine
|
||||
def handle_echo(reader, writer):
|
||||
data = yield from reader.read(100)
|
||||
async def handle_echo(reader, writer):
|
||||
data = await reader.read(100)
|
||||
message = data.decode()
|
||||
addr = writer.get_extra_info('peername')
|
||||
print("Received %r from %r" % (message, addr))
|
||||
|
||||
print("Send: %r" % message)
|
||||
writer.write(data)
|
||||
yield from writer.drain()
|
||||
await writer.drain()
|
||||
|
||||
print("Close the client socket")
|
||||
writer.close()
|
||||
|
@ -387,13 +385,13 @@ Simple example querying HTTP headers of the URL passed on the command line::
|
|||
connect = asyncio.open_connection(url.hostname, 443, ssl=True)
|
||||
else:
|
||||
connect = asyncio.open_connection(url.hostname, 80)
|
||||
reader, writer = yield from connect
|
||||
reader, writer = await connect
|
||||
query = ('HEAD {path} HTTP/1.0\r\n'
|
||||
'Host: {hostname}\r\n'
|
||||
'\r\n').format(path=url.path or '/', hostname=url.hostname)
|
||||
writer.write(query.encode('latin-1'))
|
||||
while True:
|
||||
line = yield from reader.readline()
|
||||
line = await reader.readline()
|
||||
if not line:
|
||||
break
|
||||
line = line.decode('latin1').rstrip()
|
||||
|
@ -428,19 +426,18 @@ Coroutine waiting until a socket receives data using the
|
|||
import asyncio
|
||||
from socket import socketpair
|
||||
|
||||
@asyncio.coroutine
|
||||
def wait_for_data(loop):
|
||||
async def wait_for_data(loop):
|
||||
# Create a pair of connected sockets
|
||||
rsock, wsock = socketpair()
|
||||
|
||||
# Register the open socket to wait for data
|
||||
reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop)
|
||||
reader, writer = await asyncio.open_connection(sock=rsock, loop=loop)
|
||||
|
||||
# Simulate the reception of data from the network
|
||||
loop.call_soon(wsock.send, 'abc'.encode())
|
||||
|
||||
# Wait for data
|
||||
data = yield from reader.read(100)
|
||||
data = await reader.read(100)
|
||||
|
||||
# Got data, we are done: close the socket
|
||||
print("Received:", data.decode())
|
||||
|
|
|
@ -347,21 +347,20 @@ wait for the subprocess exit. The subprocess is created by the
|
|||
def process_exited(self):
|
||||
self.exit_future.set_result(True)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_date(loop):
|
||||
async def get_date(loop):
|
||||
code = 'import datetime; print(datetime.datetime.now())'
|
||||
exit_future = asyncio.Future(loop=loop)
|
||||
|
||||
# Create the subprocess controlled by the protocol DateProtocol,
|
||||
# redirect the standard output into a pipe
|
||||
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
|
||||
sys.executable, '-c', code,
|
||||
stdin=None, stderr=None)
|
||||
transport, protocol = yield from create
|
||||
transport, protocol = await loop.subprocess_exec(
|
||||
lambda: DateProtocol(exit_future),
|
||||
sys.executable, '-c', code,
|
||||
stdin=None, stderr=None)
|
||||
|
||||
# Wait for the subprocess exit using the process_exited() method
|
||||
# of the protocol
|
||||
yield from exit_future
|
||||
await exit_future
|
||||
|
||||
# Close the stdout pipe
|
||||
transport.close()
|
||||
|
@ -398,16 +397,16 @@ function::
|
|||
code = 'import datetime; print(datetime.datetime.now())'
|
||||
|
||||
# Create the subprocess, redirect the standard output into a pipe
|
||||
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
proc = yield from create
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
sys.executable, '-c', code,
|
||||
stdout=asyncio.subprocess.PIPE)
|
||||
|
||||
# Read one line of output
|
||||
data = yield from proc.stdout.readline()
|
||||
data = await proc.stdout.readline()
|
||||
line = data.decode('ascii').rstrip()
|
||||
|
||||
# Wait for the subprocess exit
|
||||
yield from proc.wait()
|
||||
await proc.wait()
|
||||
return line
|
||||
|
||||
if sys.platform == "win32":
|
||||
|
|
|
@ -515,7 +515,7 @@ Task functions
|
|||
Example::
|
||||
|
||||
for f in as_completed(fs):
|
||||
result = yield from f # The 'yield from' may raise
|
||||
result = await f # The 'await' may raise
|
||||
# Use result
|
||||
|
||||
.. note::
|
||||
|
@ -630,11 +630,11 @@ Task functions
|
|||
|
||||
The statement::
|
||||
|
||||
res = yield from shield(something())
|
||||
res = await shield(something())
|
||||
|
||||
is exactly equivalent to the statement::
|
||||
|
||||
res = yield from something()
|
||||
res = await something()
|
||||
|
||||
*except* that if the coroutine containing it is cancelled, the task running
|
||||
in ``something()`` is not cancelled. From the point of view of
|
||||
|
@ -647,7 +647,7 @@ Task functions
|
|||
combine ``shield()`` with a try/except clause, as follows::
|
||||
|
||||
try:
|
||||
res = yield from shield(something())
|
||||
res = await shield(something())
|
||||
except CancelledError:
|
||||
res = None
|
||||
|
||||
|
@ -690,7 +690,7 @@ Task functions
|
|||
|
||||
Usage::
|
||||
|
||||
done, pending = yield from asyncio.wait(fs)
|
||||
done, pending = await asyncio.wait(fs)
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -714,7 +714,7 @@ Task functions
|
|||
|
||||
This function is a :ref:`coroutine <coroutine>`, usage::
|
||||
|
||||
result = yield from asyncio.wait_for(fut, 60.0)
|
||||
result = await asyncio.wait_for(fut, 60.0)
|
||||
|
||||
.. versionchanged:: 3.4.3
|
||||
If the wait is cancelled, the future *fut* is now also cancelled.
|
||||
|
|
|
@ -19,8 +19,9 @@ def _is_debug_mode():
|
|||
# If you set _DEBUG to true, @coroutine will wrap the resulting
|
||||
# generator objects in a CoroWrapper instance (defined below). That
|
||||
# instance will log a message when the generator is never iterated
|
||||
# over, which may happen when you forget to use "yield from" with a
|
||||
# coroutine call. Note that the value of the _DEBUG flag is taken
|
||||
# over, which may happen when you forget to use "await" or "yield from"
|
||||
# with a coroutine call.
|
||||
# Note that the value of the _DEBUG flag is taken
|
||||
# when the decorator is used, so to be of any use it must be set
|
||||
# before you define your coroutines. A downside of using this feature
|
||||
# is that tracebacks show entries for the CoroWrapper.__next__ method
|
||||
|
|
|
@ -59,7 +59,8 @@ class Future:
|
|||
# The value must also be not-None, to enable a subclass to declare
|
||||
# that it is not compatible by setting this to None.
|
||||
# - It is set by __iter__() below so that Task._step() can tell
|
||||
# the difference between `yield from Future()` (correct) vs.
|
||||
# the difference between
|
||||
# `await Future()` or`yield from Future()` (correct) vs.
|
||||
# `yield Future()` (incorrect).
|
||||
_asyncio_future_blocking = False
|
||||
|
||||
|
@ -236,7 +237,7 @@ def __iter__(self):
|
|||
if not self.done():
|
||||
self._asyncio_future_blocking = True
|
||||
yield self # This tells Task to wait for completion.
|
||||
assert self.done(), "yield from wasn't used with future"
|
||||
assert self.done(), "await wasn't used with future"
|
||||
return self.result() # May raise too.
|
||||
|
||||
__await__ = __iter__ # make compatible with 'await' expression
|
||||
|
|
|
@ -23,6 +23,10 @@ class _ContextManager:
|
|||
|
||||
with lock:
|
||||
<block>
|
||||
|
||||
Deprecated, use 'async with' statement:
|
||||
async with lock:
|
||||
<block>
|
||||
"""
|
||||
|
||||
def __init__(self, lock):
|
||||
|
@ -64,6 +68,9 @@ def __iter__(self):
|
|||
# <block>
|
||||
# finally:
|
||||
# lock.release()
|
||||
# Deprecated, use 'async with' statement:
|
||||
# async with lock:
|
||||
# <block>
|
||||
warnings.warn("'with (yield from lock)' is deprecated "
|
||||
"use 'async with lock' instead",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
|
@ -113,16 +120,16 @@ class Lock(_ContextManagerMixin):
|
|||
release() call resets the state to unlocked; first coroutine which
|
||||
is blocked in acquire() is being processed.
|
||||
|
||||
acquire() is a coroutine and should be called with 'yield from'.
|
||||
acquire() is a coroutine and should be called with 'await'.
|
||||
|
||||
Locks also support the context management protocol. '(yield from lock)'
|
||||
should be used as the context manager expression.
|
||||
Locks also support the asynchronous context management protocol.
|
||||
'async with lock' statement should be used.
|
||||
|
||||
Usage:
|
||||
|
||||
lock = Lock()
|
||||
...
|
||||
yield from lock
|
||||
await lock.acquire()
|
||||
try:
|
||||
...
|
||||
finally:
|
||||
|
@ -132,13 +139,13 @@ class Lock(_ContextManagerMixin):
|
|||
|
||||
lock = Lock()
|
||||
...
|
||||
with (yield from lock):
|
||||
async with lock:
|
||||
...
|
||||
|
||||
Lock objects can be tested for locking state:
|
||||
|
||||
if not lock.locked():
|
||||
yield from lock
|
||||
await lock.acquire()
|
||||
else:
|
||||
# lock is acquired
|
||||
...
|
||||
|
|
Loading…
Reference in New Issue