我正在使用gevent开发负载测试工具。
我创建如下测试脚本
while True:
# send http request
response = client.sendAndRecv()
gevent.sleep(0.001)
发送/接收操作非常快速地完成,例如0.1ms
因此,预期速度应接近每秒1000次。
但是实际上我在Ubuntu和Windows平台上都达到了每秒500左右的速度。
极有可能是睡眠不足。
Gevent使用libuv或libev进行内部循环。我从here
得到了以下关于libuv如何处理轮询超时的描述If the loop was run with the UV_RUN_NOWAIT flag, the timeout is 0.
If the loop is going to be stopped (uv_stop() was called), the timeout is 0.
If there are no active handles or requests, the timeout is 0.
If there are any idle handles active, the timeout is 0.
If there are any handles pending to be closed, the timeout is 0.
If none of the above cases matches, the timeout of the closest timer is taken, or if there are no active timers, infinity.
似乎当我们有gevent sleep时,实际上它将设置一个计时器,而libuv循环使用最接近的计时器的超时时间。
我真的怀疑这是根本原因:OS系统选择超时不准确!
我注意到libuv循环可以在UV_RUN_NOWAIT模式下运行,它将使循环超时为0。如果没有iOS事件,则不会休眠。
这可能会导致一个CPU内核的负载达到100%,但是我可以接受。
所以我修改了gevent代码hub.py的功能运行,如下所示
loop.run(nowait=True)
但是当我运行该工具时,我抱怨“此操作将永远阻止”,如下所示
gevent.sleep(0.001)
File "C:\Python37\lib\site-packages\gevent\hub.py", line 159, in sleep
hub.wait(t)
File "src\gevent\_hub_primitives.py", line 46, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
File "src\gevent\_hub_primitives.py", line 55, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
File "src\gevent\_waiter.py", line 151, in gevent.__waiter.Waiter.get
File "src\gevent\_greenlet_primitives.py", line 60, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src\gevent\_greenlet_primitives.py", line 60, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src\gevent\_greenlet_primitives.py", line 64, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src\gevent\__greenlet_primitives.pxd", line 35, in gevent.__greenlet_primitives._greenlet_switch
gevent.exceptions.LoopExit: This operation would block forever
那我该怎么办?
答案 0 :(得分:0)
是的,我终于找到了窍门。
如果libuv循环运行模式不是UV_RUN_DEFAULT,则gevent将进行一些检查,如果libuv循环为'nowait'模式,它将显示“此操作将永远阻止”。
那是有线的,实际上不会永远消失。
无论如何,我只是将文件libuv / loop.py的第473行修改为以下内容
if mode == libuv.UV_RUN_DEFAULT:
while self._ptr and self._ptr.data:
self._run_callbacks()
self._prepare_ran_callbacks = False
# here, change from UV_RUN_ONCE to UV_RUN_NOWAIT
ran_status = libuv.uv_run(self._ptr, libuv.UV_RUN_NOWAIT)
然后,运行加载工具,哇.....完全符合我的预期,TPS与我设置的非常接近,但是一个核心负载为100%。
那完全可以接受,因为它是负载测试工具。
因此,如果我们拥有实时OS内核,则不必费心这样做。