我有一个asyncio应用程序使用 aiohttp
的服务器和 asyncio.open_connection()
的异步套接字
我的代码包含来自PIL库的一些阻塞调用
Image.save()
Image.resize()
-
即使呼叫没有阻塞太长时间,但是,如果我使用这些阻止呼叫,我的网络服务器是否会冻结?更确切地说,由于阻塞代码,事件循环是否可能会丢失事件?
-
如果是,那些与asyncio集成的功能的替代品是什么? PIL没有asyncio版本 .
-
一般来说,在asyncio中被认为是'blocking code'?除了明显的操作,如套接字,读取文件等 .
例如,os.path.join()
被认为是好的吗?在numpy
阵列上工作怎么样?
1 回答
服务器将精确冻结执行图像功能的时间 . 您不会错过任何事件,但所有事件处理将在图像功能执行时延迟 .
冻结事件循环是一个糟糕的情况 - 你应该避免它 .
避免冻结事件循环的最简单和通用的方法 - 使用asyncio.run_in_executor在另一个线程或另一个进程中执行阻塞功能 . 代码片段显示了如何执行此操作并包含有关何时使用进程或线程的详细说明:
我只想补充说,对于每个CPU绑定操作,进程池可能并不总是很好的解决方案 . 如果您的映像功能不需要花费太多时间(特别是如果您的服务器没有多个处理器核心),那么在线程中运行它们可能仍然会更高效 .
粗略地说任何函数都是阻塞的:它会阻塞事件循环一段时间 . 但像
os.path.join
这样的许多功能花费的时间很少,所以他们称之为"blocking" .当执行时间(和事件循环冻结)成为问题时,很难说准确的限制,特别是考虑到不同硬件的时间会有所不同 . 我有偏见的建议 - 如果您的代码在将控制权返回到事件循环之前需要(或可能需要)> 50 ms,请考虑阻止并使用
run_in_executor
.Upd:
我不确定你的意思,但我想不是 . 我们需要另一个线程来运行一些工作,而不是在那里添加任务 .
等待
run_in_executor
的结果或用它开始任务 .run_in_executor
- 是一个协程,它在后台线程中执行某些操作而不阻塞事件循环 .它看起来像这样: