Python 与asyncio一起运行阻塞和取消阻塞任务

Python 与asyncio一起运行阻塞和取消阻塞任务,python,async-await,python-asyncio,Python,Async Await,Python Asyncio,我想同时异步运行阻塞和取消阻塞任务。显然,有必要使用run_in_executor方法来阻止来自asyncio的任务。以下是我的示例代码: import asyncio import concurrent.futures import datetime import time def blocking(): print("Enter to blocking()", datetime.datetime.now().time()) time.sleep(2)

我想同时异步运行阻塞和取消阻塞任务。显然,有必要使用run_in_executor方法来阻止来自asyncio的任务。以下是我的示例代码:

import asyncio
import concurrent.futures
import datetime
import time


def blocking():
    print("Enter to blocking()", datetime.datetime.now().time())
    time.sleep(2)
    print("Exited from blocking()", datetime.datetime.now().time())


async def waiter():
    print("Enter to waiter()", datetime.datetime.now().time())
    await asyncio.sleep(3)
    print("Exit from waiter()", datetime.datetime.now().time())


async def asynchronous(loop):
    print("Create tasks", datetime.datetime.now().time())
    task_1 = asyncio.create_task(waiter())

    executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)
    task_2 = loop.run_in_executor(executor, blocking)

    tasks = [task_1, task_2]
    print("Tasks are created", datetime.datetime.now().time())
    await asyncio.wait(tasks)


if __name__ == "__main__":
    try:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(asynchronous(loop))
    except (OSError) as exc:
        sys.exit('Exception: ' + str(exc))
我应该使用相同的事件循环来阻止run_in_executor中的任务,还是必须使用另一个事件循环?为了使代码异步工作,我应该在代码中更改什么?谢谢

您必须使用相同的循环。循环委托给执行器,执行器运行的任务是事件循环的独立线程。因此,您不必担心阻塞任务会阻塞事件循环。如果使用单独的循环,事件循环中的异步函数将无法等待阻止在新循环中运行的函数的结果

事件循环通过创建表示执行者任务的未来来管理这一点。然后,它在其中一个执行器线程中运行阻塞任务,当执行器任务返回未来的结果时,将设置并将控制返回到事件循环中的等待函数(如果有)。

必须使用相同的循环。循环委托给执行器,执行器运行的任务是事件循环的独立线程。因此,您不必担心阻塞任务会阻塞事件循环。如果使用单独的循环,事件循环中的异步函数将无法等待阻止在新循环中运行的函数的结果


事件循环通过创建表示执行者任务的未来来管理这一点。然后,它在其中一个执行器线程中运行阻塞任务,当执行器任务返回未来的结果时,将设置并将控制返回到事件循环中的等待函数(如果有)。

非常感谢。那么上面的代码似乎是正确的?创建了一个事件循环,用于阻塞和非阻塞任务。这很好,只是您应该避免在异步函数中传递事件循环-这可能会导致错误。相反,如果异步函数需要访问事件循环,请使用asyncio.get_running_循环。这是3.7中的新功能,如果您使用3.6或更低版本,请使用get_event_循环。非常感谢。那么上面的代码似乎是正确的?创建了一个事件循环,用于阻塞和非阻塞任务。这很好,只是您应该避免在异步函数中传递事件循环-这可能会导致错误。相反,如果异步函数需要访问事件循环,请使用asyncio.get_running_循环。这在3.7中是新的,所以如果您使用3.6或更低版本,请使用get_event_loop。除了答案所说的,请注意,您不需要为每次运行创建新的线程池。线程池的要点是重用线程以提高效率。您只需将None作为第一个参数传递给运行_in_executor,并让它使用asyncio为事件循环创建的线程池。哦,我明白了。但如果我不使用自定义线程拉取中的独立线程,它将使用事件循环阻止线程,不是吗?我不是说你应该使用线程池,我只是说你不需要创建自己的线程池。将None传递给run_in_executor将使用asyncio自己的线程池,该线程池就是为此而存在的。该线程池仍然有自己的线程,并且不会阻止事件池线程。我只是被官方文档中的这个短语弄糊涂了:loop.run\u in\u executor方法可以与concurrent.futures.ThreadPoolExecutor一起使用,在不同的OS线程中执行阻塞代码,而不会阻塞事件循环运行的OS线程。我认为默认情况下只有一个线程具有事件循环,并且使用您自己的线程池,您将避免使用事件循环阻塞主线程。您认为正确的是,实际上只有一个线程运行事件循环。这个线程池是为您这样的情况提供的一个助手,以避免每个人都创建自己的线程池和线程数量无限制地增长。因此,您确实必须使用线程池,但它不一定是您自己的-asyncio提供的线程池与运行事件循环的线程不同,这是非常好的。除了答案所说的,请注意,您不需要为每次运行创建新的线程池。线程池的要点是重用线程以提高效率。您只需将None作为第一个参数传递给运行_in_executor,并让它使用asyncio为事件循环创建的线程池。哦,我明白了。但如果我不使用自定义线程拉取中的独立线程,它将使用事件循环阻止线程,不是吗?我不是说你应该使用线程池,我只是说你不需要创建自己的线程池。将None传递给run_in_executor将使用asyncio自己的线程池,该线程池就是为此而存在的。该线程池仍然有自己的线程,并且不会阻止事件池线程。我只是对官方文档中的这个短语感到困惑:loop.run_in_executor方法可以与c语言一起使用
oncurrent.futures.ThreadPoolExecutor在不同的OS线程中执行阻塞代码,而不阻塞事件循环运行的OS线程。我认为默认情况下只有一个线程具有事件循环,并且使用您自己的线程池,您将避免使用事件循环阻塞主线程。您认为正确的是,实际上只有一个线程运行事件循环。这个线程池是为您这样的情况提供的一个助手,以避免每个人都创建自己的线程池和线程数量无限制地增长。因此,您确实必须使用线程池,但它不一定是您自己的-asyncio提供的线程池与运行事件循环的线程不同,这是非常好的。