表现
一个父进程里多个线程并发地调用 subprocess.Popen 来创建子进程的时候, 会有几率出现 Popen 长时间不返回的情况.
这个问题是由于fd被多个子进程同时继承导致的.
重现问题的代码
下面这个小程序启动2个线程, 每个线程各自(通过 subprocess.Popen )启动一个子进程, 一个子进程执行 echo 1 后就直接返回; 另一个子进程启动后, sleep 0.03 秒后返回.
程序里统计了2个调用 Popen 花的时间, 运行后可以发现, echo的进程有时启动很快(小于预期的0.01秒, 仅仅是启动, 不包括执行时间), 有时会很慢(超过0.03秒), 刚好和另一个sleep的进程执行时间吻合. 调大sleep子进程的时间可以看到echo也会同样有几率返回慢.
# > cat slow.py
import threading
import subprocess
import time
def _open(cmd, expect):
t0 = time.time()
proc = subprocess.Popen(
cmd,
shell=True,
# # without this line, some Popen does not return at once as expected
# close_fds=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
spent = time.time() - t0
if spent > expect:
print cmd + ' spent: ' + str(spent)
pro