我已经研究了这个问题,并在这里进行了关于stackoverflow的研究。我遵循了这些线程中的建议,但是到目前为止,对我来说什么都没有解决(我认为我对基本知识尚不了解):
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脚本在一个窗口/控制台中运行,然后我希望每个模型/模拟都生成自己的窗口/控制台,以便可以独立监视每个模拟(或实际上可以通过以下方式暂停/停止/终止):只需关闭窗口)。
当我从编辑器中运行Python脚本时(我已经尝试了Enthought Canopy和IDLE),该脚本完全按预期工作,并为每个模拟生成了单独的窗口。但是,如果我通过在Windows资源管理器中双击它或从Windows命令提示符处调用它来运行Python脚本,则各个模拟不会生成自己的窗口。它们都将输出直接转储到同一窗口中,从而造成困惑的困惑(并且也不允许我通过关闭其单独的窗口来终止仿真)。
为了解决我的问题,我尝试遵循上述链接中的所有建议。这包括使用shell = True,使用Windows“启动”命令,重定向输出管道等的各种不同组合。这些解决方案都不适合我。
我觉得我不明白为什么我的脚本可以在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. Sebastian在下面的评论,我现在有了工作代码。关键是在命令行开头使用“cmd.exe/c start“NAME”“,将所有内容作为字符串而不是列表进行连接,然后将命令行字符串传递给带有shell的subprocess.call() =是的。因此,工作代码为:
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. Sebastian)的评论,我现在有了工作代码。关键是在命令行开头使用“cmd.exe/c start“NAME”“,将所有内容作为字符串而不是列表进行连接,然后将命令行字符串传递给带有shell的subprocess.call() =是的。因此,工作代码为:
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()