You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于gevent的monkey.patch_all导致subprocess.check_call执行变慢的问题

解决gevent monkey.patch_all导致subprocess.check_call变慢的问题

这确实是gevent monkey补丁使用中很常见的一个坑,我来给你拆解下原因和对应的解决办法:

问题根源

当你调用patch_all()时,gevent默认会替换标准库中的subprocess模块,改成适配协程的版本。但这个协程兼容版为了实现非阻塞IO和协程间同步,会做额外的封装与处理——对于像iptables -L -vx这种输出量较大、依赖系统内核操作的命令来说,这些额外处理反而会带来明显的性能开销,直接导致执行时间变长。

解决方案

根据你的业务场景,有几种不同的处理方式:

1. 全局禁用subprocess的补丁

如果你的代码里不需要让subprocess支持协程(比如所有subprocess调用都是同步阻塞的,不影响其他协程执行),最简单的办法就是在patch时排除subprocess:

from gevent.monkey import patch_all; patch_all(subprocess=False)
import subprocess
from subprocess import STDOUT
from tempfile import NamedTemporaryFile
import datetime

with NamedTemporaryFile() as f:
    print('Subprocess call at {}'.format(datetime.datetime.now()))
    ret = subprocess.check_call(['iptables', '-t', 'mangle', '-L', '-vx'], stdout=f, stderr=STDOUT)
    print('Subprocess call end at {}'.format(datetime.datetime.now()))

这样subprocess会保持标准库的原生实现,执行速度就会恢复正常。

2. 针对特定调用使用原始subprocess函数

如果你的其他代码依赖于gevent patched后的subprocess,只需要个别调用恢复原生速度,那可以在patch之前先保存原始的check_call函数:

# 先导入原始subprocess,保存需要的函数
import subprocess
original_check_call = subprocess.check_call

# 再执行全量补丁
from gevent.monkey import patch_all; patch_all()

from subprocess import STDOUT
from tempfile import NamedTemporaryFile
import datetime

with NamedTemporaryFile() as f:
    print('Subprocess call at {}'.format(datetime.datetime.now()))
    # 调用原始的check_call函数
    ret = original_check_call(['iptables', '-t', 'mangle', '-L', '-vx'], stdout=f, stderr=STDOUT)
    print('Subprocess call end at {}'.format(datetime.datetime.now()))

或者也可以用gevent提供的get_original方法获取原始函数:

from gevent.monkey import patch_all; patch_all()
from gevent import get_original
import subprocess
from subprocess import STDOUT
from tempfile import NamedTemporaryFile
import datetime

# 获取原始的check_call
original_check_call = get_original('subprocess', 'check_call')

with NamedTemporaryFile() as f:
    print('Subprocess call at {}'.format(datetime.datetime.now()))
    ret = original_check_call(['iptables', '-t', 'mangle', '-L', '-vx'], stdout=f, stderr=STDOUT)
    print('Subprocess call end at {}'.format(datetime.datetime.now()))

3. 优化gevent subprocess的配置(进阶)

如果必须使用patched后的subprocess,可以尝试调整gevent的subprocess相关配置,比如修改IO缓冲方式或使用更高效的子进程通信机制,但这种方式比较复杂,通常前两种方案已经能解决大部分场景的问题。

内容的提问来源于stack exchange,提问作者lz96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:26:00