我的同事问我为什么他的代码不能多线程并发运行。我发现
os.system
函数的行为与多线程中的其他函数不同。我编写了一个小演示来重现该问题。感谢能够回答我问题的人。
import os
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
executor = ThreadPoolExecutor()
begin = time.time()
for _ in as_completed([
executor.submit(os.system, cmd)
for cmd in ['sleep 10', 'sleep 3', 'sleep 2']
]):
print("completed after", time.time() - begin, "seconds")
输出
completed after 10.005892276763916 seconds
completed after 13.017478942871094 seconds
completed after 15.034425258636475 seconds
将
os.system
替换为 subprocess.call
。
import subprocess
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
executor = ThreadPoolExecutor()
begin = time.time()
for _ in as_completed([
executor.submit(subprocess.call, cmd, shell=True)
for cmd in ['sleep 10', 'sleep 3', 'sleep 2']
]):
print("completed after", time.time() - begin, "seconds")
输出
completed after 2.019604206085205 seconds
completed after 3.017033338546753 seconds
completed after 10.009897232055664 seconds
os.system
是通过调用标准C函数实现的system
:
这是通过调用标准C函数
来实现的,并且 具有相同的限制。system()
system
函数的手册页:
在等待子进程终止时阻塞
可以防止 应用程序捕获信号并获取状态SIGCHLD
的子进程在system()
之前可以获取状态本身。system()
和:
在进程中的多个线程中使用
函数或 当system()
信号被多个线程操作时 在一个过程中可能会产生意想不到的结果。SIGCHLD
由于
SIGCHLD
在执行过程中必须被阻塞,所以并发调用system
是行不通的。
另一方面,subprocess.Popen
(subprocess.call
函数使用的底层类)在不阻塞fork
的情况下处理exec
/wait
/SIGCHLD
,因此可以并发执行。