在PyQt中控制异步线程 - 多线程还是多处理?

时间:2013-11-27 20:43:20

标签: python multithreading pyqt multiprocessing

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

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架构兼容吗?如何传入和传出值?如何终止?

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

2 个答案:

答案 0 :(得分:1)

您的问题听起来与我的研究小组解决的问题非常相似。不幸的是,它写在PyGTK(Qt的端口有希望在6-12个月内发生)。无论如何,labscript套件中名为lyse的程序可以满足您的需求。它非常复杂,但是查看源代码可能足以让您入门。

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

如果您对项目有任何具体问题(如果有任何用途),请随时查看http://www.labscriptsuite.org上的源代码,其中还包含开发人员联系人。有很多部分不依赖于GTK,因此如果您愿意,可以将其包含在Qt程序中。关于项目的大部分信息(以及包含的程序)都包含在我们在系统上发布的论文中(如果您无法访问RSI,则可以在FAQ页面上找到该论文的下载链接)

答案 1 :(得分:0)

似乎我找到了至少解决我问题中最关键部分的解决方案 - 中止线程我的mian线程:http://tomerfiliba.com/recipes/Thread2/

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

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