是否可以在不生成线程或进程的情况下在后台启动异步事件循环?

Is it possible to start an asyncio event loop in the background without spawning a thread or process?

我在 Python 3.5 中实现了一项服务,该服务应定期通过网络加载文件。我想避免在加载时阻塞主线程。为了避免在我的应用程序中引入线程和共享内存的复杂性,我想使用带有 asyncio 包的事件循环来对此进行检测。

到 运行 一个事件循环,我找到了 AbstractEventLoop.run_forever()AbstractEventLoop.run_until_complete(future) 方法,但它们在调用时似乎都阻塞了主线程。我发现避免这种情况的唯一方法是在不同的线程中启动循环。但是如果我无论如何都在使用线程,那么使用事件循环就没有意义了。

所以我的问题是:是否可以在不生成线程或进程的情况下在后台启动异步事件循环?

您可以使用run_in_executor方法。 运行 使用此方法的每个函数 运行 在它们自己的线程中(并行)。

The AbstractEventLoop.run_in_executor() method can be used with a thread pool executor to execute a callback in different thread to not block the thread of the event loop.

The executor argument should be an Executor instance. The default executor is used if executor is None.

例如:

import asyncio

def load_file_over_network(file_name):
    # do the file loading
    pass

loop = asyncio.get_event_loop()
file_name = 'FILE_NAME'

# load the file without blocking
loop.run_in_executor(None, load_file_over_network, file_name)

# do some other stuff in the main thread
# while the synchronous code above is running in other threads, the event loop
# can go do other things

# load the file again without blocking
loop.run_in_executor(None, load_file_over_network, file_name)

希望这对您有所帮助:)

如果您的整个程序在没有 asyncio 的事件循环的情况下运行,那么 运行 在新的事件循环中只有一个任务没有多大意义。相反,请尝试使用更简单的 concurrent.futures 库。任何调用的任务都会立即 return 一个 Future 实例,它有一个 .done().result() 方法:

import time
from concurrent.futures.thread import ThreadPoolExecutor


def fetcher():
    print("fetching...")
    time.sleep(2)
    print("got it!")
    return 42


with ThreadPoolExecutor(max_workers=10) as executor:
    fut = None
    for i in range(100):
        if i % 10 == 2:
            fut = executor.submit(fetcher)
        print(i, fut)
        if fut and fut.done():
            result = fut.result()  # can raise an error
            print("Done! Got:", result)
            fut = None
        time.sleep(0.5)

嗯,loop.run_in_executor() is right, partially. Indeed, the Executor 参数可以是 ThreadPoolExecutor(默认),或 ProcessPoolExecutor

所以答案是否定的,您不能 运行 一个 asyncio Task 在后台与所有其他代码同步。或者您重写您的应用程序,使其对每个任务都使用 asyncio,或者您必须使用线程或进程。