首页 > 解决方案 > 我可以在等待子进程 Popen 的同时在另一个线程中工作吗

问题描述

我有一个 Python 3.7 项目

它正在使用一个库,该库使用子进程Popen调用 shell 脚本。

我想知道:如果将库调用放在一个单独的线程中,我是否能够在等待Popen另一个线程的结果时在主线程中工作?

这里有一个答案https://stackoverflow.com/a/33352871/202168说:

Python 线程使用 GIL 的方式是使用一个简单的计数器。每执行 100 字节代码,GIL 应该由当前正在执行的线程释放,以便给其他线程执行代码的机会。由于线程释放/获取机制,这种行为在 Python 2.7 中基本上被破坏了。它已在 Python 3 中修复。

无论哪种方式听起来对我想做的事情都没有特别的希望。听起来如果“库调用”线程在调用时没有达到 100 字节码触发点,Popen.wait那么它可能不会切换到我的另一个线程并且整个应用程序将等待子进程?

然而,也许这个信息是错误的。

这是另一个答案https://stackoverflow.com/a/16262657/202168说:

...解释器总是可以释放 GIL;它会在解释了足够多的指令后将其提供给其他线程,或者如果它执行一些 I/O 则自动将其提供给其他线程。请注意,从最近的 Python 3.x 开始,标准不再基于执行指令的数量,而是基于是否经过了足够的时间。

这听起来更有希望,因为可能与子进程的通信将涉及 I/O,因此可能允许我的主线程的上下文切换能够同时进行。(或者也许只是等待的时间wait会导致上下文切换)

我知道https://docs.python.org/3/library/asyncio-subprocess.html明确解决了这个问题,但我正在调用一个仅使用 plain 的 3rd-party 库subprocess.Popen

任何人都可以确认“在单独的线程中调用子进程”的想法是否可能对我有用,特别是在 Python 3.7 中?

标签: python-3.xmultithreadingsubprocessgil

解决方案


我有时间做一个实验,所以我会回答我自己的问题......

我设置了两个文件:

mainthread.py

#!/usr/bin/env python
import subprocess
import threading
import time


def run_busyproc():
    print(f'{time.time()} Starting busyprocess...')
    subprocess.run(["python", "busyprocess.py"])
    print(f'{time.time()} busyprocess done.')


if __name__ == "__main__":
    thread = threading.Thread(target=run_busyproc)
    print("Starting thread...")
    thread.start()
    while thread.is_alive():
        print(f"{time.time()} Main thread doing its thing...")
        time.sleep(0.5)
    print("Thread is done (?)")
    print("Exit main.")

busyprocess.py

#!/usr/bin/env python
from time import sleep


if __name__ == "__main__":
    for _ in range(100):
        print("Busy...")
        sleep(0.5)
    print("Done")

从命令行运行mainthread.py,我可以看到您希望看到的上下文切换 - 主线程能够在等待子进程的结果时完成工作:

Starting thread...
1555970578.20475 Main thread doing its thing...
1555970578.204679 Starting busyprocess...

Busy...
1555970578.710308 Main thread doing its thing...
Busy...
1555970579.2153869 Main thread doing its thing...
Busy...
1555970579.718168 Main thread doing its thing...
Busy...
1555970580.2231748 Main thread doing its thing...
Busy...
1555970580.726122 Main thread doing its thing...
Busy...
1555970628.009814 Main thread doing its thing...

Done
1555970628.512945 Main thread doing its thing...

1555970628.518155 busyprocess done.
Thread is done (?)
Exit main.

大家好消息,python线程工作:)


推荐阅读