为什么gevent会影响子线程的asyncio使用?

问题描述 投票:0回答:1
  • gevent版本:20.10.2
  • Python版本:cPython 3.9
  • 操作系统:macOS 14.3.1(M3)

描述:

我的程序使用了gevent patch,但是在程序中,我需要在子线程中执行asyncio相关的代码 当多个子线程执行同一个协程时,会触发“RuntimeError:此事件循环已在运行” 它们是不同的线程,我为每个子线程生成了自己的事件循环,我无法理解这个问题 当我注释掉猴子补丁时,程序按照我的预期执行了

ERROR:root:This event loop is already running
Traceback (most recent call last):
  File "/Users/computer1/pytest/test.py", line 30, in func1
    loop.run_until_complete(asyncf1())
  File "/opt/homebrew/Cellar/[email protected]/3.9.18_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 623, in run_until_complete
    self._check_running()
  File "/opt/homebrew/Cellar/[email protected]/3.9.18_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 583, in _check_running
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
/Users/computer1/pytest/test.py:32: RuntimeWarning: coroutine 'asyncf1' was never awaited
  logging.error(e, exc_info=True)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
ERROR:root:This event loop is already running
Traceback (most recent call last):
  File "/Users/computer1/pytest/test.py", line 30, in func1
    loop.run_until_complete(asyncf1())
  File "/opt/homebrew/Cellar/[email protected]/3.9.18_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 623, in run_until_complete
    self._check_running()
  File "/opt/homebrew/Cellar/[email protected]/3.9.18_2/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 583, in _check_running
    raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running

我跑过的:

import logging

import gevent.monkey
gevent.monkey.patch_all()
import concurrent.futures

import threading
import time
import asyncio

pool = concurrent.futures.ThreadPoolExecutor()

async def asyncf1():
    print("aa")
def func1():
    # print(f"thread:{threading.get_ident()},gevent:{id(gevent.getcurrent())}")
    try:
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            loop = asyncio.new_event_loop()
            # asyncio.set_event_loop(loop)
        loop.run_until_complete(asyncf1())
    except Exception as e:
        logging.error(e, exc_info=True)
    print(threading.current_thread())
    time.sleep(3)


for i in range(3):
    pool.submit(func1)

time.sleep(10)

python multithreading python-asyncio gevent
1个回答
0
投票

是否有强烈需要混合

gevent
asyncio
?据我所知,它们是针对类似问题的两种不同的解决方案。我不太清楚它们是否可以轻松混合。但看来你的问题与
gevent
无关。

据我所知,您的问题是您实际上并没有(至少总是)在自己的线程上启动

asyncio
事件循环。您将您的
func1
提交到线程 pool,而不一定是单独的、唯一的线程。我想你不会每次都会遇到这个错误,因为这取决于线程池如何在每次 for 循环迭代中将
func1
分配给线程。可能还有一些竞争条件。

asyncio
事件循环必须位于其自己的线程上,并且在事件循环期间它实际上拥有整个线程。因此,您应该为要运行的每个事件循环显式创建一个线程。

请参阅这些答案:


最后,目前尚不清楚您需要多个事件循环而不是仅使用一个事件循环。多个事件循环(因此多个线程)将比单个事件循环(因此单个线程)慢,并且我看不到多个事件循环有任何实际好处。

© www.soinside.com 2019 - 2024. All rights reserved.