2013-11-27 125 views
0

我正在PyQt开发一个应用程序(主要是Windows,但未来打算去多平台),它专注于处理某些数字数据,所以核心基本上是围绕numpy数组和matplotlib图表构建的。不过,我想让系统的一部分Python脚本化,允许用户稍微调整数据处理。他们编写的脚本代码存储在一个字符串中,只需要传入和传出一些arbirtary类型的参数。并添加一些错误处理,以及...这可以以非常简单的方式在Python代码片段在这里实现,如:控制PyQt中的异步线程 - 多线程或多处理?

global_dict = {} # values could go in here 
local_dict = {} # values could go in here 
try: 
    exec(script_code, global_dict, local_dict) 
    value = local_dict[variable_name] # value out 
#etc... 

的问题是,用户脚本是在我的掌握中,用户可以编写他们喜欢的任何内容,并且可以花费大量时间执行可能会冻结GUI的内容。所以我需要去多线程。我已经有一个工作解决方案。我使用从QtCore.QRunnable运行继承的类和上面的代码异步。它工作正常,并在脚本完成时正确通知GUI线程,传递结果并销毁线程。但我仍然有三个严重的问题:

1)一个关键问题:如何中止脚本执行?尽管异步脚本不会冻结GUI,但它可能非常长或甚至无限。用户当然必须有选择放弃执行而不必终止整个应用程序。这对于QRunnable来说似乎不可行。所以我想到了从QRunnable切换到已终止方法的QThread。但严格不建议使用此方法。应用程序如何从其一个线程的终止中恢复,这是非常令人怀疑的,例如,在传入脚本的对象引用计数时会发生什么情况。这个问题甚至可以解决吗?我不知道......也许有一个我看不到的神奇解决方案。 Python多处理模块可以提供帮助吗?

2)一个重要的问题:由于用户可以通过脚本传入和传出数据,这是通过引用完成的,他们也可以更改数据。在Python多线程中,GIL确保没有两个线程同时写入相同的数据,但可能发生数据已被处理或显示在应用程序的另一部分中。所以我需要将脚本输入写入脚本,当用户尝试写入时抛出异常。它甚至有可能吗?

3)一个不错的解决方案,但它可以生存的问题:有时几个脚本可以同时执行。由于Python的GIL,所有线程仅在一个解释器和一个处理器内核中执行。这可能是性能的限制。据我了解,为了从多处理器内核中受益,我需要从多线程切换到多处理。但如何在给定的情况下做到这一点?它是否与PyQt架构兼容?如何传入和传出值?如何终止?

也许我问得太多了,也许我的愿望不是来自这个现实。不过,我会非常感谢任何暗示或建议或资料来源。

+0

也许我已经找到了解决方案,至少我的问题... killable线程的一部分:[链接](http://tomerfiliba.com/recipes/Thread2/)...我要测试它。 –

+0

为什么这会得到downvoted?意见? – neuronet

回答

0

似乎我已经找到了解决方案,至少是我的问题的最关键的部分 - 放弃一个线程我的线程:http://tomerfiliba.com/recipes/Thread2/

根据该链接,它使用函数PyThreadState_SetAsyncExc在另一个线程中引发异常。它看起来很简单,根据我的第一个测试,它在Windows上运行Python 3非常完美。

,我将尽力找到解决我的其他问题。但如果没有,我现在可以接受这个解决方案。

1

您的问题听起来与我的研究小组已解决的问题非常相似。不幸的是,它写在PyGTK(Qt的一个端口将在6-12个月内有希望发生)。无论如何,实验室套件中的lyse程序会执行很多你所要求的操作。这非常复杂,但也许看着源代码可能足以让你开始。

简而言之,我们有一个在一个进程中运行的GUI,在另一个进程中运行的任意用户代码(这个进程也有其他线程和伟大的它是自己的图窗口),并通过发送pandas传递数据(使用numpy )数据帧并通过PyZMQ(0MQ)套接字发送它们。

如果您有任何关于该项目的具体问题(应该有任何用处),请随时查看我们的源代码http://www.labscriptsuite.org,其中还包含开发人员联系人。有相当多的部分不依赖于GTK,如果你愿意的话,可以包含在Qt程序中。该项目(并列入计划)的大多数信息都包含在我们的系统上发表的论文(如果你没有获得RSI,有FAQ页面上的下载链接文件)

+0

非常感谢你的来源,我很感激。我会检查你提供的代码。然而,在我完成所有依赖关系的安装之前,您能否确认它具有我正在寻找的功能?我的意思是中止在另一个线程或进程中运行一个脚本执行,而不会破坏应用程序的其他部分或离开内存泄漏的能力... –

+0

我不一定会担心项目的完整安装(但你可以,如果你喜欢)。代码的特定部分是模块subproc_utils和lyse/analysis_subprocess.py。 subproc_utils应该只需要pyzmq,并且有一些如何在两个进程之间建立连接的例子。然后,您可以传入要运行到子进程的python脚本的文件路径,并使用execfile()来运行它。因为一切都在一个独立的进程中,所以当进程被终止时,OS负责清理内存。所以要中止,只需要杀死一个子进程。 –

+1

因此,在短期,最好的办法是多进程架构,采用类似zeromq(0MQ)进行通信。子进程使用execfile或exec来运行你的arbiratry Python代码。您可以通过杀死子进程来终止正在运行的scipt。这有避免GIL问题的额外好处。这方面的例子实现在labscript套件程序裂解(您可以通过从脚本列表中删除它来执行,刚刚杀死子“中止”的脚本):) –