asyncio时间循环中运行阻塞任务

 场景:

在某个异步循环中 需要执行某个阻塞任务(例如文件读写., 保存图片等)

如果这个时候直接在异步事件循环中直接运行, 那么所有任务都会阻塞在这里, 明显是不行的

 

解决方案:

https://docs.python.org/3/library/asyncio-eventloop.html#executing-code-in-thread-or-process-pools

 

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)

# 在某个异步事件循环中
async def main():
    loop = asyncio.get_running_loop()  # 获取当前事件循环

    result = await loop.run_in_executor(None, blocking_io)

    with concurrent.futures.ThreadPoolExecutor() as pool:
          result = await loop.run_in_executor(
            pool, blocking_io)
          print('custom thread pool', result)

asyncio.run(main())

 

loop.run_in_exeutor(pool, func)

pool为线程池 在python里面为concurrent.futures.ThreadPoolExecutor的实例

func为需要运行的同步函数 如果需要传入参数, 要用functools.partial(func, *arg, **kwargs)  传入.

 

运行之后, 则会在不阻塞异步时间循环的情况下 ,在新的线程中运行func 结束之后用await接收

 

如果一开始不指定线程池,那么官方文档中说的是默认线程池

这里的默认线程池可以用

loop.set_default_executor(executor)

来指定

如果一开始也不指定, 那么经过阅读源码之后 可知:

    def run_in_executor(self, executor, func, *args):
        self._check_closed()
        if self._debug:
            self._check_callback(func, 'run_in_executor')
        if executor is None:
            executor = self._default_executor
            if executor is None:
                executor = concurrent.futures.ThreadPoolExecutor()
                self._default_executor = executor
        return futures.wrap_future(
            executor.submit(func, *args), loop=self)

他会帮我们自动启用一个线程池, 丢进去运行.

 

总之异步的时间循环中如果要加入阻塞型代码,  千万不能直接阻塞, 用此法可破.

posted @ 2020-04-01 22:03  冰糖雪梨橙  阅读(944)  评论(0编辑  收藏  举报