Python 3.x 为什么asyncio会阻塞processPool?

Python 3.x 为什么asyncio会阻塞processPool?,python-3.x,asynchronous,python-asyncio,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

我有以下代码:

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
我认为如果我们在进程池上运行代码,它不会阻塞主循环。但是在输出中,它在阻塞函数完成后返回到主事件循环


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

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

使用协程的原因主要是为了处理I/O活动。如果您正在等待消息,只需检查一个套接字,如果什么也没有发生,您将返回主循环。然后,在控件最终返回IO函数之前,可以处理其他协程

在您的情况下,使用
wait asyncio.sleep(x)
而不是
time.sleep(x)
是有意义的。这样,在睡眠时间内,将从
阻塞_func()
暂停控制。之后,控件返回到那里,结果应该与您预期的一样


更多信息:

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

使用协程的原因主要是为了处理I/O活动。如果您正在等待消息,只需检查一个套接字,如果什么也没有发生,您将返回主循环。然后,在控件最终返回IO函数之前,可以处理其他协程

在您的情况下,使用
wait asyncio.sleep(x)
而不是
time.sleep(x)
是有意义的。这样,在睡眠时间内,将从
阻塞_func()
暂停控制。之后,控件返回到那里,结果应该与您预期的一样


更多信息:

这里的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)

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)

进程池中是否有多个可以并行执行的进程?是的,它就是这样做的。它是
循环。运行\u in\u executor()
调用以并行方式启动阻塞代码,而不是
表达式中生成。此调用返回类
Future
的对象,该对象表示最终可用的值。在你们有了对未来对象的引用之后,你们可以在主进程中做你们想做的任何事情,它将是非阻塞的。当您最终需要blocking func中的值时,您可以调用
yield from future
-此函数将阻塞,直到值为available@AndriyMaletsky一个小问题:
等待循环。在执行器(…)中运行并不一定是无用的。虽然它确实阻止了当前的协同进程,但它并没有阻止整个父进程;它仍然允许其他协同程序运行。当协程需要进程池的结果来继续其工作时,使用
wait
阻止协程是一项功能。在OP希望并行运行多个这样的调用的情况下,这是没有用的,所有调用都来自同一个协程。是的,我的意思是完全属于OP的情况,但我的说法似乎太强了,因为进程池中会有多个进程,可以并行执行?是的,这就是它所做的。它是
循环。运行\u in_executor()
调用,并行启动阻塞代码,而不是
表达式中生成。此调用返回类
Future
的对象,该对象表示最终可用的值。在你们有了对未来对象的引用之后,你们可以在主进程中做你们想做的任何事情,它将是非阻塞的。当您最终需要blocking func中的值时,您可以调用
yield from future
-此函数将阻塞,直到值为available@AndriyMaletsky一个小问题:
等待循环。在执行器(…)中运行并不一定是无用的。虽然它确实阻止了当前的协同进程,但它并没有阻止整个父进程;它仍然允许其他协同程序运行。当协程需要进程池的结果来继续其工作时,使用
wait
阻止协程是一项功能。在OP希望并行运行几个这样的调用的情况下,这是没有用的,所有调用都来自同一个协同程序。是的,我的意思是OP的情况,但我的陈述似乎太强烈了,感谢进程池是否意味着我们有多个进程可以并行运行代码?进程池是否意味着我们有多个进程可以并行运行代码?