在文章"I'm not feeling the async pressure"中,Armin Ronacher进行了以下观察:
在线程代码中,任何函数都可以产生。在异步代码中,只有异步函数可以。例如,这意味着writer.write方法无法阻止。
此观察是参考以下代码示例进行的:
from asyncio import start_server, run
async def on_client_connected(reader, writer):
while True:
data = await reader.readline()
if not data:
break
writer.write(data)
async def server():
srv = await start_server(on_client_connected, '127.0.0.1', 8888)
async with srv:
await srv.serve_forever()
run(server())
我不明白此评论。具体来说:
yield
?yield
与阻止执行有什么关系?为什么不能yield
不能阻塞的功能?逐行:
在线程代码中,任何函数都可以产生。
在计算机上运行的程序是根据进程来组织的。每个进程可能具有一个或多个threads。线程(如进程)由操作系统调度(并可由操作系统中断)。在此上下文中,单词“ yield”表示“让其他代码运行”。将工作分配到多个线程之间时,函数很容易“屈服”:操作系统将一个线程中运行的代码挂起,在另一个线程中运行一些代码,将其挂起,返回,然后在第一个线程上进行更多工作,等等。上。通过以这种方式在线程之间切换,可以实现并发。
在此执行模型中,被挂起的代码是同步还是异步无关紧要。线程中的代码[[inin是逐行运行的,因此不违反同步函数的基本假设-在运行一行代码和下一行代码之间不发生任何更改-。
在异步代码中,只有异步函数可以。
“异步代码”在本文中是指与多线程应用程序执行相同工作的单线程应用程序,不同之处在于它通过使用异步函数
within
线程而不是分割工作< [之间不同的线程。在此执行模型中,解释器(而不是操作系统)负责根据需要在功能之间进行切换以实现并发性。在此执行模型中,将工作挂在位于异步函数内部的同步函数中间是不安全的。这样做将意味着在运行同步功能的过程中运行其他一些代码,从而破坏了同步功能所做的“逐行”假设。结果,解释器将仅等待同步子功能之间的异步功能的执行挂起,而不会等待一个。这就是异步代码中的同步函数无法产生的语句的含义:一旦同步函数开始运行,它就必须完成。例如,这意味着writer.write方法无法阻止。
块,这样做是不明智的。writer.write
方法是同步的,因此,在异步程序中运行时,它是不间断的。如果要阻塞此方法,则它不仅会阻塞正在其内部运行的异步函数,还会阻塞整个程序。那将是不好的。writer.write
通过改为写入写缓冲区并立即返回来避免阻塞程序。严格来说,
writer.write
can
如果您需要在异步函数内部进行阻塞,则正确的方法是await
另一个异步函数。这就是例如await writer.drain()
可以。这将异步阻止:尽管此特定功能仍然处于阻止状态,但它将正确地屈服于可以运行的其他功能。