如何在Python中为线程设置asyncio事件循环?

Rud*_*lah 7 python multithreading python-3.x python-asyncio

我正在尝试创建两个线程,每个线程都有自己的asyncio事件循环.

我尝试了以下代码,但它似乎不起作用:

import asyncio
from threading import Thread

def hello(thread_name):
    print('hello from thread {}!'.format(thread_name))

event_loop_a = asyncio.new_event_loop()
event_loop_b = asyncio.new_event_loop()

def callback_a():
    asyncio.set_event_loop(event_loop_a)
    asyncio.get_event_loop().call_soon_threadsafe(lambda: hello('a'))

def callback_b():
    asyncio.set_event_loop(event_loop_b)
    asyncio.get_event_loop().call_soon_threadsafe(lambda: hello('b'))

thread_a = Thread(target=callback_a, daemon=True)
thread_b = Thread(target=callback_b, daemon=True)
thread_a.start()
thread_b.start()
Run Code Online (Sandbox Code Playgroud)

我的用例是调用Tornado web框架的websocket_connect异步函数.

use*_*342 7

您的线程正在各自的事件循环中对回调进行排队,但是它们在实际运行事件循环之前就退出了,因此这些回调永远不会执行。而且,您不需要call_soon_threadsafe,因为您是从运行(或将要运行)事件循环的同一线程调用回调的。

此代码输出预期的输出:

import asyncio
from threading import Thread

def hello(thread_name):
    print('hello from thread {}!'.format(thread_name))

event_loop_a = asyncio.new_event_loop()
event_loop_b = asyncio.new_event_loop()

def callback_a():
    asyncio.set_event_loop(event_loop_a)
    asyncio.get_event_loop().call_soon(lambda: hello('a'))
    event_loop_a.run_forever()

def callback_b():
    asyncio.set_event_loop(event_loop_b)
    asyncio.get_event_loop().call_soon(lambda: hello('b'))
    event_loop_b.run_forever()

thread_a = Thread(target=callback_a, daemon=True)
thread_b = Thread(target=callback_b, daemon=True)
thread_a.start()
thread_b.start()
Run Code Online (Sandbox Code Playgroud)

更加典型的用例(call_soon_threadsafe更符合您的想法)是向asyncio.run_coroutine_threadsafe在另一个线程中运行的事件循环提交回调(或使用的协程)。这是一个例子:

import asyncio, threading

def hello(thread_name):
    print('hello from thread {}!'.format(thread_name))

event_loop_a = asyncio.new_event_loop()
event_loop_b = asyncio.new_event_loop()

def run_loop(loop):
    asyncio.set_event_loop(loop)
    loop.run_forever()

threading.Thread(target=lambda: run_loop(event_loop_a)).start()
threading.Thread(target=lambda: run_loop(event_loop_b)).start()

event_loop_a.call_soon_threadsafe(lambda: hello('a'))
event_loop_b.call_soon_threadsafe(lambda: hello('b'))

event_loop_a.call_soon_threadsafe(event_loop_a.stop)
event_loop_b.call_soon_threadsafe(event_loop_b.stop)
Run Code Online (Sandbox Code Playgroud)

在那种情况下,几乎不需要一个以上的事件循环线程-您通常只创建一个,并允许该线程满足您所有的异步需求。毕竟,能够在单个事件循环中托管大量任务是asyncio的强项之一。

  • @RudolfOlah如果您喜欢`call_soon_threadsafe`,还可以签出[`asyncio.run_coroutine_threadsafe`](https://docs.python.org/3/library/asyncio-task.html#asyncio.run_coroutine_threadsafe),该功能可用于安排时间事件循环线程中的_coroutine_,并返回允许等待的[`concurrent.futures.Future`](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future)使协程完成而不会导致死锁。 (2认同)