为什么asyncio会被processPool阻塞?

时间:2018-04-27 09:40:21

标签: python-3.x asynchronous python-asyncio

我有以下代码:

import time
import asyncio
from concurrent.futures import ProcessPoolExecutor

def blocking_func(x):
    print("In blocking waiting")
    time.sleep(x) # Pretend this is expensive calculations
    print("after blocking waiting")
    return x * 5

@asyncio.coroutine
def main():
    executor = ProcessPoolExecutor()

    out = yield from loop.run_in_executor(executor, blocking_func, 2)  # This does not
    print("after process pool")
    print(out)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

输出:

In blocking waiting
after blocking waiting
after process pool
10

但是我期待进程池将在不同的进程中运行代码。所以我期待输出为:

期待输出:

In blocking waiting
after process pool
after blocking waiting
10

我想如果我们在进程池上运行代码就不会阻塞主循环。但是在输出完成后,它会在阻塞函数完成后回到主事件循环。

阻止事件循环的是什么?是阻塞功能吗?如果是blocking_function,那么使用进程池有什么用呢?

2 个答案:

答案 0 :(得分:2)

yield from这里意味着"等待协程完成并返回其结果"。与Python线程API相比,它就像调用join()

要获得所需的结果,请使用以下内容:

@asyncio.coroutine
def main():
    executor = ProcessPoolExecutor()

    task = loop.run_in_executor(executor, blocking_func, 2)
    # at this point your blocking func is already running
    # in the executor process

    print("after process pool")

    out = yield from task

    print(out)

答案 1 :(得分:1)

协同程序不是单独的进程。不同之处在于协程需要自己放弃对循环的控制。这意味着如果你有一个阻塞协程,那么它将阻止整个循环。

使用协同程序的原因主要是处理I / O活动。如果您正在等待消息,则只需检查套接字即可,如果没有任何反应,您将返回主循环。然后可以在最终控制返回到IO功能之前处理其他协同程序。

在您的情况下,使用await asyncio.sleep(x)代替time.sleep(x)是有意义的。这样,控制在休眠时间内从blocking_func()暂停。然后控制返回那里,结果应该如你所愿。

更多信息:https://docs.python.org/3/library/asyncio.html

相关问题