python - 在脱离主线程的异步事件循环中运行无限循环

标签 python python-multithreading python-asyncio

我编写的代码似乎可以满足我的要求,但我不确定这是否是个好主意,因为它混合了线程和事件循环以在主线程之外运行无限循环。这是一个最小的代码片段,它捕捉了我正在做的事情的想法:

import asyncio
import threading

msg = ""

async def infinite_loop():
    global msg
    while True:
        msg += "x"
        await asyncio.sleep(0.3)

def worker():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    asyncio.get_event_loop().run_until_complete(infinite_loop())

t = threading.Thread(target=worker, daemon=True)
t.start()

主要思想是我有一个无限循环,每 0.3 秒处理一个全局变量。我希望这个无限循环在主线程之外运行,这样我仍然可以访问主线程中的共享变量。这在 jupyter 中特别有用,因为如果我在主线程中调用 run_until_complete,我将无法再与 jupyter 交互。我希望主线程可用于交互访问和修改 msg。在我的示例中使用异步似乎没有必要,但我正在使用具有异步代码的库来运行服务器,因此这是必要的。我是 python 中异步和线程的新手,但我记得在某个地方读过/听到过将线程与 asyncio 一起使用是自找麻烦……这是个坏主意吗?我的方法是否存在任何潜在的并发问题?

最佳答案

I'm new to async and threading in python, but I remember reading / hearing somewhere that using threading with asyncio is asking for trouble...

不鼓励初学者混合使用 asyncio 和线程,因为它会导致不必要的复杂化,并且通常源于对如何正确使用 asyncio 缺乏理解。刚接触 asyncio 的程序员通常会习惯性地使用线程,将它们用于协程更适合的任务。

但是,如果您有充分的理由生成运行异步事件循环的线程,请务必这样做——没有什么需要在主线程中运行异步事件循环。只需要注意与事件循环本身的交互(调用方法,例如 call_sooncreate_taskstop 等)运行事件循环,即来自 asyncio 协程和回调。要安全地与其他线程(例如您的主线程)的事件循环交互,请使用 loop.call_soon_threadsafe()asyncio.run_coroutine_threadsafe() .

请注意,设置全局变量等不算作“交互”,因为 asyncio 不观察这些。当然,由您来处理线程间同步问题,例如使用锁保护对复杂可变结构的访问。

is this a bad idea?

如果不确定是否混合使用线程和异步,您可以问自己两个问题:

  • 考虑到 asyncio 提供并行运行的协程和 run_in_executor,我还需要线程吗?等待阻塞代码?
  • 如果我有提供并行性的线程,我真的需要 asyncio 吗?

您的问题对这两个问题都提供了很好的答案 - 您需要线程以便主线程可以与 jupyter 交互,并且您需要 asyncio 因为您依赖于使用它的库。

Are there any potential concurrency issues with my approach?

GIL 确保在一个线程中设置全局变量并在另一个线程中读取它不会发生数据竞争,因此您所展示的内容应该没问题。

如果添加显式同步,例如多线程队列或条件变量,则应记住同步代码不得阻塞事件循环。换句话说,您不能只等待一个 threading.Event。在 asyncio 协程中,因为那样会阻塞所有协程。相反,您可以等待 asyncio.Event ,并使用来自其他线程的 loop.call_soon_threadsafe(event.set) 之类的设置。

关于python - 在脱离主线程的异步事件循环中运行无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49584561/

相关文章:

python - 如何在 pandas Series 对象上并行化 `map` 函数?

python - 如何在 Outlook (2010) 全局地址列表中搜索多个姓名?

python - 比较 Python 中的性能 : equal versus non equal

python - 使用 xmlrpc 与 openerp 的并发连接被拒绝(通过 python)

python - 打印功能使多处理程序失败

Python Webdriver 多线程

python - 如何将协程添加到正在运行的事件循环中?

python - 处理 python 脚本中的 wlst 异常

python - 如何将 Asyncio 与 while 循环一起使用

docker - 为什么打印不能与异步生成器一起正常工作?