1

背景:
*我正在使用 Tkinter(便携式 PYscripter,python v2.7.3)创建批量模拟作业选择器 + 调度器
*此程序将用作商业求解器程序的前端
*该程序需要允许用户选择一堆文件,一个接一个地依次模拟。
*它还需要能够从现有/正在运行的作业列表中修改(添加/删除)作业。
*每次模拟肯定会运行几个小时。
*模拟的输出将在单独的程序上查看,我不需要任何管道连接到输出。需要时,将从 GUI 调用外部查看器。

***我有一个主 GUI 窗口,它允许用户:
选择作业文件、提交作业、查看提交日志、停止运行作业(一个接一个)
上面的效果很好。

问题:
*如果我使用 subprocess.Popen("command") :所有模拟输入文件同时启动。它必须是连续的(由于许可证和内存限制)

*如果我使用 subprocess.call(" ") 或 wait() 方法,那么 GUI 挂起并且没有范围来停止/添加/修改作业列表。即使“作业提交”命令位于独立窗口上,两个父窗口也会挂起,直到作业完成。

问题 1:
*如何按顺序启动模拟作业(如 subprocess.call)并允许主 GUI 窗口运行以修改作业列表或停止作业?
这些作业在一个列表中,使用“askopenfilenames”获取,然后使用 For 循环运行。

守则的相关部分:

cfx5solvepath=r"c:\XXXX"
def file_chooser_default(): 
    global flist1
    flist1=askopenfilename(parent = root2, filetypes =[('.def', '*.def'),('All', '*.*'),('.res', '*.res')], title ="Select Simulation run files...", multiple = True)[1:-1].split('} {')

def ext_process():
    o=list(flist1)
    p=list(flist1)
    q=list(flist1)
    i=0
    while i < len(flist1):
        p[i]='"%s" -def "%s"'%(cfx5solvepath,flist1[i])
        i+=1
    i=0
    while i < len(p):
        q[i]=subprocess.call(p[i])
        i+=1

root2 = Tk()
root2.minsize(300,300)
root2.geometry("500x300")
root2.title("NEW WINDOW")
frame21=Frame(root2, borderwidth=3, relief="solid").pack()
w21= Button(root2,fg="blue", text="Choose files to submit",command=file_chooser_default).pack()
w2a1=Button(root2,fg="white", text= 'Display chosen file names and order', command=lambda:print_var(flist1)).pack()
w2b1= Button (root2,fg="white", bg="red", text="S U B M I T", command=ext_process).pack()
root2.mainloop()

如果您需要其他任何东西,请告诉我。期待您的帮助。

*编辑 *
在合并@Tim 建议的更改时,GUI 是免费的。由于有一个与主求解器程序关联的特定子程序来停止作业,因此我可以使用正确的命令停止作业。

一旦当前正在运行的作业停止,列表中的下一个作业就会自动启动,正如我所希望的那样。

这是用于停止作业的代码:

def  stop_select(): #Choose the currently running files which are to be stopped
    global flist3
    flist3=askdirectory().split('} {')

def sim_stop(): #STOP the chosen simulation
    st=list(flist3)
    os.chdir("%s"%flist3[0])
    st= subprocess.call('"%s" -directory "%s"'%(defcfx5stoppath,flist3[0]))
    ret1=tkMessageBox.showinfo("INFO","Chosen simulation stopped successfully")
    os.chdir("%s" %currentwd)



问题 2: *一旦完成上述作业,使用 start_new_thread,GUI 没有响应。GUI 在作业在后台运行时工作。但是start_new_thread文档说线程应该在函数返回时静默退出。

*此外,我有一个 HTML 日志文件,在每个作业完成时都会写入/更新。当我使用 start_new_thread 时,日志文件内容只有在所有作业完成后才可见。然而,内容以及时间戳是正确的。在不使用 start_new_thread 的情况下,我能够刷新 HTML 文件以获取更新的提交日志。

***在使用任务管理器多次退出GUI程序时,我突然无法使用start_new_thread函数!我也尝试过重新安装 PYscripter 并重新启动计算机。我无法从回溯中找出任何合理的东西,即:

Traceback (most recent call last):
File "<string>", line 532, in write
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 439, in _async_request
seq = self._send_request(handler, args)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 229, in _send_request
self._send(consts.MSG_REQUEST, seq, (handler, self._box(args)))
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\protocol.py", line 244, in _box
if brine.dumpable(obj):
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in dumpable
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in <genexpr>
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in dumpable
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\lib\site-packages\rpyc\core\brine.py", line 369, in <genexpr>
return all(dumpable(item) for item in obj)
File "C:\Portable Python 2.7.3.1\App\Python_Working_folder\v350.py", line 138, in ext_process
q[i]=subprocess.call(p[i])
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 493, in call
return Popen(*popenargs, **kwargs).wait()
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 679, in __init__
errread, errwrite)
File "C:\Portable Python 2.7.3.1\App\lib\subprocess.py", line 896, in _execute_child
startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
4

1 回答 1

0

我建议使用单独的线程来启动作业。最简单的方法是使用模块中的start_new_thread方法thread

将提交按钮的命令更改为command=lambda:thread.start_new_thread(ext_process, ())

您可能希望在单击按钮时禁用它,并在启动完成时启用它。这可以在里面完成ext_process

如果您想允许用户取消作业,它会变得更加复杂。该解决方案无法处理。

于 2012-11-20T06:04:44.943 回答