aiogevent 事件循环“未能”跟踪 greenlets
Posted
技术标签:
【中文标题】aiogevent 事件循环“未能”跟踪 greenlets【英文标题】:aiogevent event loop "fails" to track greenlets 【发布时间】:2019-06-24 14:26:12 【问题描述】:我最近偶然发现了混淆基于 gevent 和 asyncio 的代码的问题,因为当我使用 gevent.monkey.patch_all()
对它们进行猴子补丁时,一些同步库工作得很好。我找到了aiogevent
库,它似乎对实现 PEP 3156 有所帮助,并将 asyncio 事件循环替换为您选择的另一个实现(在本例中是 gevent)。我发现对 git 存储库的最后一次重大提交是在 4 年前进行的。修复 setup.py 后,我成功安装了它,但问题是它没有通过所有测试。
其中一个测试是test_soon,它会生成应该执行操作并停止循环的greenlet。这个测试永远挂起,因为loop.stop()
对循环没有任何影响,预计在所有任务完成后会停止。我写了两个 sn-ps 来检查它是否发生在传统协程中,另一个是通过 gevent.spawn
使用 greenlets。
import gevent
import aiogevent
import asyncio
asyncio.set_event_loop_policy(aiogevent.EventLoopPolicy())
loop = asyncio.get_event_loop()
async def func():
print('bloop')
loop.stop()
loop.create_task(func())
loop.run_forever() # works alright and stops as soon as func finish
还有gevent.spawn
:
import gevent
import aiogevent
import asyncio
asyncio.set_event_loop_policy(aiogevent.EventLoopPolicy())
loop = asyncio.get_event_loop()
def func():
print('bloop')
loop.stop()
g = gevent.spawn(func)
loop.run_forever() # func is executed as soon as loop runs, but loop.stop() is ignored
还有一个问题:这里可能出现什么问题?我清楚地看到greenlet在我开始循环后运行,但它被循环“未跟踪”?我在 asyncio 源代码中找不到与此机制相对应的确切行,对于 gevent 也是如此 - 我对这些模块的内部不太熟悉,搜索它们很混乱,但我想知道有什么不同和必须对aiogevent
的事件循环进行哪些更改才能通过测试。
upd1:为了强调这个问题,gevent.hub.Hub
没有“公共”句柄来停止循环,只有那些应该完全破坏它的句柄(gevent.hub.get_hub().destroy()
目前没有效果,并且如果未在 MAIN greenlet 中调用,则尝试加入 hub greenlet 失败)。它确实有在循环退出时引发的内部异常 (gevent.exceptions.LoopExit
)。我的想法是找到如何捕获这个异常的方法,并将其与 run_forever 绑定,但还没有结果。
【问题讨论】:
【参考方案1】:对此进行猜测,但我认为您将事件循环用于 asyncio 是错误的。 我对 gevent 的了解还不够,无法理解它正在创建什么类型的对象以知道这是否会起作用。documentation 将表明 stop() 和 run_forever() 的调用顺序与操作调用栈相关,内容如下:
如果在调用 run_forever() 之前调用了 stop(),则循环将轮询 I/O 选择器一次,超时时间为零,运行所有为响应 I/O 事件而调度的回调(以及那些已经调度的回调) ),然后退出。
如果在 run_forever() 运行时调用了 stop(),则循环将运行当前批次的回调然后退出。请注意,回调安排的新回调在这种情况下不会运行;相反,它们将在下次调用 run_forever() 或 run_until_complete() 时运行。
我假设此选项用于控制异步事件的状态,但您可能会发现run_until_complete()
可能是您更好的选择,它可能是这样的:
import gevent
import aiogevent
import asyncio
asyncio.set_event_loop_policy(aiogevent.EventLoopPolicy())
loop = asyncio.get_running_loop()
async def func():
await print('bloop') # await keyword not needed, just demonstrating
loop.stop()
try:
loop.run_until_complete(gevent.spawn(func))
finally:
loop.run_until_complete(loop.shutdown_asyncgens())
loop.close()
我添加了shutdown_asyncgens()
,以防您正在等待导致close()
方法挂起/失败的yield 响应。我没有安装任何这些来测试,所以让我知道这是否有帮助。
【讨论】:
有趣。所以从技术上讲,如果我按照您的说明添加greenlets,我可以安全地将当前形式的aiogevent放入项目中吗?如果可能的话,你能帮我修复测试吗?我也会尝试做一些研究并维护项目,我对内部的了解还不够。 从技术上讲,如果我明确地将 greenlets 传递给run_until complete
,它应该可以工作,但我不确定在当前程序中不知道 asyncio 的情况下创建的那些。我考虑过删除一些测试并添加新的,但我可能错了。我所需要的只是能够拼接使用 asyncio 和 gevent 的两段不同的代码,并确保它们都由 aiogevent 提供的相同事件循环调度,所有等待等。如果我可以创建一个问题并在那里继续对话您希望提供帮助,在此先感谢。【参考方案2】:
为什么不直接使用这样的 while 循环:
from time import sleep
while(1 == 1):
print('bloop')
sleep(1)
这将打印 bloop 等待一秒钟然后再次打印(因为 1 = 1),如果我错了,请原谅我,你必须使用你正在使用的功能,但我已经尽力了。
【讨论】:
所以你认为 OP 只是想每 1 秒打印一次 bloop,但想多了,认为使用事件循环很有用? 问题不在于打印 bloops。我只是提供了显示问题的最少代码。以上是关于aiogevent 事件循环“未能”跟踪 greenlets的主要内容,如果未能解决你的问题,请参考以下文章
跟踪器:错误 TRK0005:未能找到:“CL.exe”。该系统找不到指定的文件
安装oracle11的时候 提示ORA-28056 未能将审计记录写入windows事件日志,这是怎么回事啊