Могу ли я работать в другом потоке в ожидании подпроцесса Popen - PullRequest
0 голосов
/ 21 апреля 2019

У меня есть проект Python 3.7

Он использует библиотеку, которая использует подпроцесс Popen для вызова сценария оболочки.

Мне интересно: если бы я поместил вызовы библиотеки в отдельный поток, смог бы ли я выполнять работу в основном потоке, ожидая результата от 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; это даст это некоторым другой поток после того, как он интерпретировал достаточно инструкций, или автоматически, если это делает некоторый ввод / вывод. Обратите внимание, что с недавнего Python 3.x, критерии больше не основаны на количестве выполненных инструкции, но относительно того, прошло ли достаточно времени.

Это звучит более обнадеживающе, поскольку предположительно связь с подпроцессом потребует ввода-вывода и, следовательно, может позволить переключению контекста для моего основного потока, чтобы он мог продолжаться в это время. (или, возможно, только что прошедшее время ожидания на wait вызовет переключение контекста)

Мне известно о https://docs.python.org/3/library/asyncio-subprocess.html, который явно решает эту проблему, но я вызываю стороннюю библиотеку, которая просто использует простой subprocess.Popen.

Может ли кто-нибудь подтвердить, может ли идея "вызовы подпроцесса в отдельном потоке" быть мне полезной, особенно в Python 3.7?

1 Ответ

0 голосов
/ 23 апреля 2019

У меня было время провести эксперимент, поэтому я отвечу на свой вопрос ...

Я настроил два файла:

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 работает :)

...