如何在 Python 中为线程设置异步事件循环? [英] How do I set the asyncio event loop for a thread in Python?

查看:112
本文介绍了如何在 Python 中为线程设置异步事件循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create two threads that each have their own asyncio event loop.

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

I've tried the following code but it doesn't seem to work:

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()

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

My use case is calling Tornado web framework's websocket_connect async function.

推荐答案

您的线程正在它们各自的事件循环中排队回调,但它们在实际运行事件循环之前退出,因此回调永远不会得到执行.此外,您不需要 call_soon_threadsafe,因为您是从同一线程调用回调,事件循环正在(或者更确切地说,将)运行.

Your threads are queuing callbacks in their respective event loops, but they exit before actually running the event loop, so the callbacks never get executed. Also, you don't need call_soon_threadsafe, since you are invoking the callback from the same thread the event loop is (or, rather, will be) running on.

此代码打印预期的输出:

This code prints the expected output:

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()

call_soon_threadsafe 的一个更典型的用例,并且更符合您的想法,是提交回调(或使用 asyncio.run_coroutine_threadsafe) 到另一个线程中运行的事件循环.下面是一个例子:

A more typical use case for call_soon_threadsafe, and more in line with what you might have had in mind, is to submit a callback (or a coroutine using asyncio.run_coroutine_threadsafe) to an event loop running in another thread. Here is an example:

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)

在这种情况下,很少需要有多个事件循环线程——您通常只创建一个,并允许该线程满足您所有的异步需求.毕竟,能够在单个事件循环中承载大量任务是 asyncio 的强项之一.

In that case it is rarely needed to have more than one event loop thread - you'd typically create only one, and allow that thread to service all your asyncio needs. After all, being able to host a large number of tasks in a single event loop is one of the strong points of asyncio.

这篇关于如何在 Python 中为线程设置异步事件循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆