Python 子进程在没有睡眠的情况下无法工作

Python subprocess doesn't work without sleep

我正在开发一个 Python 启动器,它应该通过调用 subprocess 来执行我列表中的一些程序。代码是正确的,但是运行起来很奇怪

简而言之,如果 sleepinput 命令在 main[=40= 中,它就无法工作].

示例如下:

import threading
import subprocess
import time

def executeFile(file_path):
  subprocess.call(file_path, shell=True)


def main():
  file = None

  try:
      file = open('./config.ini', 'r');
  except:
    # TODO: add alert widget
    print("cant find a file")

  pathes = [ path.strip() for path in file.readlines() ]

  try:
    for idx in range(len(pathes)):
        print(pathes[idx])
        file_path = pathes[idx];
        newThread = threading.Thread(target=executeFile, args=(file_path,))
        newThread.daemon = True
        newThread.start()
  except:
    print("cant start thread")


  if __name__ == '__main__':
    main()

    # IT WORKS WHEN SLEEP EXISTS
    time.sleep(10)

    # OR
    # input("Press enter to exit ;)")

但没有 inputsleep 它不起作用:

if __name__ == '__main__':
   # Doesn't work
   main()

谁能解释一下,为什么会这样?

我有一些想法,但我不确定。可能是因为 subprocess 是异步的,程序在子进程执行之前执行并自行关闭。

sleepinput 的情况下,程序暂停并且 subprocess 有足够的时间执行。

感谢您的帮助!

一旦启动最后一个线程,您的 main() returns。这反过来将退出您的 Python 程序。这会停止您的所有线程。

来自关于守护线程的文档:

Note: Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.

简单的解决方法是使用守护线程。


顺便说一句,我建议对您的循环进行一些更改。首先,直接迭代 pathes 而不是使用索引。第二;分别捕获每个线程的错误,因此一个错误不会留下未处理的剩余文件。

for path in pathes:
    try:
        print(path)
        newThread = threading.Thread(target=executeFile, args=(path,))
        newThread.start()
    except:
        print("cant start thread for", path)

另一种选择是完全跳过线程,只维护 运行 个子进程的列表:

import os
import subprocess
import time


def manageprocs(proclist):
    """Check a list of subprocesses for processes that have
       ended and remove them from the list.

    :param proclist: list of Popen objects
    """
    for pr in proclist:
        if pr.poll() is not None:
            proclist.remove(pr)
    # since manageprocs is called from a loop,
    # keep CPU usage down.
    time.sleep(0.5)


def main():

    # Read config file
    try:
        with open('./config.ini', 'r') as f:
            pathes = [path.strip() for path in f.readlines()]
    except FileNotFoundError:
        print("cant find config file")
        exit(1)

    # List of subprocesses
    procs = []
    # Do not launch more processes concurrently than your
    # CPU has cores.  That will only lead to the processes
    # fighting over CPU resources.
    maxprocs = os.cpu_count()
    # Launch all subprocesses.
    for path in pathes:
        while len(procs) == maxprocs:
            manageprocs(procs)
        procs.append(subprocess.Popen(path, shell=True))
    # Wait for all subprocesses to finish.
    while len(procs) > 0:
        manageprocs(procs)


if __name__ == '__main__':
    main()