首页 > 解决方案 > Python 子进程在没有睡眠的情况下无法工作

问题描述

我正在开发一个 Python 启动器,它应该通过调用子进程来执行我列表中的一些程序。代码是正确的,但它的工作方式非常奇怪。

简而言之,如果没有一些sleepmain中的输入命令,它就无法工作。

这是示例:

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 ;)")

但没有输入睡眠它不起作用:

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

请有人解释一下,为什么会这样?

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

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

谢谢你的帮助!

标签: pythonasynchronoussubprocesslaunch

解决方案


一旦最后一个线程开始,你的main()回报。这反过来将退出您的 Python 程序。这会停止你所有的线程。

从守护线程的文档中:

注意:守护线程在关闭时突然停止。它们的资源(如打开的文件、数据库事务等)可能无法正常释放。如果您希望线程优雅地停止,请将它们设为非守护进程并使用合适的信号机制,例如事件。

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


顺便说一句,我建议对您的循环进行一些更改。首先,直接迭代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()

推荐阅读