Python 2.7 - 如何在使用线程时为单个 subprocess.call() 任务生成单独的 Windows 控制台?

Python 2.7 - How to spawn separate Windows consoles for individual subprocess.call() tasks when using threading?

我已经探讨了这个问题,并在这里对 Whosebug 进行了研究。我遵循了这些线程中的建议,但到目前为止没有任何效果(我想我不理解一些基本的东西):

How can I spawn new shells to run python scripts from a base python script?

Opening a Python thread in a new console window

Execute terminal command from python in new terminal window?

我有一个脚本将模拟列表获取到 运行(使用单独的 Windows 程序),并使用线程到 运行 n 并行的模型数量,而不是像普通的 Windows 批处理文件那样纯粹按顺序排列。该模型通常会向 Windows 控制台输出一堆信息,以便您可以监控其进度。在我的例子中,我希望主 Python 脚本在一个 window / 控制台中 运行,然后我希望每个模型/模拟产生自己的 window / 控制台所以每个模拟都可以独立监控(或者实际上通过简单地关闭 window 来暂停/停止/终止)。

当我在我的编辑器中 运行 Python 脚本时(我已经尝试过 Enthought Canopy 和 IDLE),脚本完全按预期工作,单独的 windows为每个模拟生成。但是,如果我 运行 Python 脚本通过在 Windows 资源管理器中双击它或从 Windows 命令提示符调用它,单个模拟不会产生自己的 windows。他们都将他们的输出直接转储到同一个 window 中,造成混乱(并且不允许我通过关闭其个人 window 来终止模拟)。

为了解决我的问题,我已尝试遵循上述链接中的所有建议。这包括使用 shell=True、使用 Windows "start" 命令、重定向输出管道等的各种不同组合。这些解决方案中的 None 对我有用.

我觉得我不明白为什么我的脚本在 Canopy / IDLE 中按预期工作,但在直接从命令提示符 运行 时却不起作用。

我的脚本如下:

from time import sleep
import threading
from subprocess import call

def runmodel(arg):
    call(arg)
    sGlobal.release()

if __name__ == '__main__':    

    n = 6 # maximum number of simultaneous runs
    s = 15 # delay between starts in seconds

    simulations = [] # big list of simulations to run in here - each item in list is another list containing the seperate arguments in the command line

    threads = []
    global sGlobal

    sGlobal = threading.Semaphore(n)

    for arg in simulations:
        sGlobal.acquire()
        t = threading.Thread(target=runmodel, args=(arg,))
        threads.append(t)
        t.start()
        sleep(s)

    for t in threads:
        t.join()

作为参考,运行 模拟的 Windows 命令行看起来像这样(在我的实际脚本中有一个很大的列表 - 在每个 Python 脚本中命令作为列表而不是字符串传递给 subprocess.call):

"<full file path to model executable>" -some -flags -here "<full file path to model control file>"  

如果有任何意见可以帮助我更好地理解或解决我的问题,我将不胜感激。

编辑:澄清每个命令行作为列表而不是字符串传递给subprocess.call。

编辑 2:感谢 J.F,我现在有了工作代码。塞巴斯蒂安在下面的评论。关键是在我的命令行开头使用 'cmd.exe /c start "NAME"' ,将所有内容作为字符串而不是列表连接起来,然后将命令行字符串传递给 subprocess.call() 和 shell =是的。因此,工作代码是:

from time import sleep
import threading
from subprocess import call

def runmodel(arg):
    call(arg, shell=True) # not the addition of shell=True - this is now required as the command line is being passed as a string rather than a list - I could not get the syntax with quotation marks and everything else to work without using a string and shell=True.
    sGlobal.release()

if __name__ == '__main__':    

    n = 6 # maximum number of simultaneous runs
    s = 15 # delay between starts in seconds

    simulations = ['cmd.exe /c start "NAME" "<full file path to model exe>" -some -flags -here "<full file path to model control file>"'] # big list of simulations to run in here - each item in list is a string that represents the full command line to run a simulation

    threads = []
    global sGlobal

    sGlobal = threading.Semaphore(n)

    for arg in simulations:
        sGlobal.acquire()
        t = threading.Thread(target=runmodel, args=(arg,))
        threads.append(t)
        t.start()
        sleep(s)

    for t in threads:
        t.join()

感谢 J.F,我现在有了工作代码。塞巴斯蒂安的评论。关键是在我的命令行开头使用 'cmd.exe /c start "NAME"' ,将所有内容作为字符串而不是列表连接起来,然后将命令行字符串传递给 subprocess.call() 和 shell =是的。因此,工作代码是:

from time import sleep
import threading
from subprocess import call

def runmodel(arg):
    call(arg, shell=True) # not the addition of shell=True - this is now required as the command line is being passed as a string rather than a list - I could not get the syntax with quotation marks and everything else to work without using a string and shell=True.
    sGlobal.release()

if __name__ == '__main__':    

    n = 6 # maximum number of simultaneous runs
    s = 15 # delay between starts in seconds

    simulations = ['cmd.exe /c start "NAME" "<full file path to model exe>" -some -flags -here "<full file path to model control file>"'] # big list of simulations to run in here - each item in list is a string that represents the full command line to run a simulation

    threads = []
    global sGlobal

    sGlobal = threading.Semaphore(n)

    for arg in simulations:
        sGlobal.acquire()
        t = threading.Thread(target=runmodel, args=(arg,))
        threads.append(t)
        t.start()
        sleep(s)

    for t in threads:
        t.join()