我最近偶然发现了将gevent和基于异步的代码混合在一起的问题,因为当我用gevent.monkey.patch_all()
对它们进行猴子补丁时,一些同步库就可以正常工作。我找到了aiogevent
库,它似乎可以通过实现PEP 3156来帮助您,并将asyncio事件循环替换为您选择的其他实现(在本例中为gevent)。我发现的git仓库的最后一次重大提交是在4年前。修复setup.py之后,我设法成功安装了它,但是问题是它没有通过所有测试。
其中一个测试是test_soon,它会产生应该执行操作并停止循环的greenlet。该测试将永远挂起,因为loop.stop()
对循环没有任何影响,该循环预计将在所有任务完成后停止。我写了两个摘要来检查它是否与传统的协程一起发生,而另一个则通过gevent.spawn
与greenlet一起发生。
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会运行,但是循环会“跟踪”它吗?我在异步源中找不到与该机制相对应的确切行,对于gevent来说也是如此-我对这些模块的内部并不十分熟悉,并且通过它们进行搜索令人困惑,但是我想知道有什么区别和为了通过测试,必须对aiogevent
的事件循环进行哪些更改。
upd1 :为了强调这个问题,gevent.hub.Hub
没有“公共”句柄来停止循环,只有那些应该完全销毁循环的人(gevent.hub.get_hub().destroy()
目前拥有无效,如果未在MAIN Greenlet中调用,则尝试加入中心Greenlet将失败。当循环退出(gevent.exceptions.LoopExit
)时,它确实会引发内部异常。我的想法是找到如何捕获此异常的方法,并将其与run_forever绑定在一起,但尚无结果。
答案 0 :(得分:2)
对此进行猜测,但是我认为您对asyncio使用了错误的事件循环。 我对gevent不太了解,无法了解它正在创建哪种类型的对象。 documentation将表明stop()和run_forever()的顺序被调用与操作调用堆栈有关,内容如下:
如果在调用run_forever()之前调用了stop(),则循环将以0的超时轮询一次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()
方法挂起/失败。我没有安装这些工具来进行测试,所以请告诉我这是否有帮助。
答案 1 :(得分:-2)
为什么不只使用while循环:
from time import sleep
while(1 == 1):
print('bloop')
sleep(1)
这将打印bloop等待一秒钟,然后再次打印(因为1 = 1),如果我错了,请原谅我,并且您必须使用所使用的功能,但是我尽力了。