asyncio 中执行阻塞代码
对我来说,异步编程模式更接近现实世界。使用异步模式完成复杂任务比使用多线程或者多进程模式更容易让人理解,缺点是不太好调试,现有的调试工具对同步模式的支持更成熟一些。异步模式下,要求所有的代码都是非阻塞的。一旦那一行代码是阻塞的,整个系统就会失去响应。
在python中,很多常用的API的基本上都是阻塞的。文件读写、控制台的读写、request等都是基于同步阻塞的编程模式设计的。怎么解决这个矛盾呢?如果不想全部用异步模式重新实现那些API,当然就只能把阻塞的代码放到单独的线程或进程里了。因此在实际的项目中,就算我们使用异步模式,也不可避免的要用到同步多线程或者多进程模式。如果接受不了,请选择Nodejs 吧。在NodeJS里,绝大部分API都是异步的。
asyncio 提供了一个API(run_in_executor)可以方便地在线程池\进程池运行阻塞代码。
import asyncio
import concurrent.futures
def blocking_io():
# File operations (such as logging) can block the
# event loop: run them in a thread pool.
with open('/dev/urandom', 'rb') as f:
return f.read(100)
def cpu_bound():
# CPU-bound operations will block the event loop:
# in general it is preferable to run them in a
# process pool.
return sum(i * i for i in range(10 ** 7))
async def main():
loop = asyncio.get_running_loop()
## Options:
# 1. Run in the default loop's executor:
result = await loop.run_in_executor(
None, blocking_io)
print('default thread pool', result)
# 2. Run in a custom thread pool:
with concurrent.futures.ThreadPoolExecutor() as pool:
result = await loop.run_in_executor(
pool, blocking_io)
print('custom thread pool', result)
# 3. Run in a custom process pool:
with concurrent.futures.ProcessPoolExecutor() as pool:
result = await loop.run_in_executor(
pool, cpu_bound)
print('custom process pool', result)
asyncio.run(main())