在应用程序执行大量CPU处理时保持GUI响应是有效GUI编程的挑战之一。
Here's a good discussion如何在wxPython中执行此操作。总而言之,有三种方式:
哪种方法你发现最有效?其他框架(如Qt,GTK或Windows API)的技术也很受欢迎。
答案 0 :(得分:15)
主题。它们是我一直以来的目标,因为您可以在您需要的每个框架中实现它。
一旦你习惯了在一种语言/框架中进行多线程和并行处理,你就会对所有框架都很擅长。
答案 1 :(得分:7)
绝对是线程。为什么?未来是多核的。几乎任何新的CPU都有一个以上的核心,或者如果它只有一个核心,它可能支持超线程,因此假装它不止一个。为了有效地利用多核CPU(英特尔计划在不远的将来达到32个核心),您需要多个线程。如果你在一个主线程中运行所有(通常UI线程是主线程),用户将拥有8,16和一天32核的CPU,你的应用程序永远不会使用多个,IOW它运行得多,速度慢得多比它可以运行。
实际上如果你现在计划一个应用程序,我会放弃经典设计并想到主/从关系。您的UI是主要的,它的唯一任务是与用户进行交互。这是向用户显示数据并收集用户输入。每当你的应用程序需要“处理任何数据”(甚至少量和更重要的大数据)时,创建任何类型的“任务”,将此任务转发到后台线程并使线程执行任务,向用户界面(例如,已完成的百分比或者任务是否仍在运行,因此用户界面可以显示“正在进行的工作指标”)。如果可能,将任务拆分为许多小的独立子任务,并运行多个后台进程,为每个子任务提供一个子任务。这样,您的应用程序就可以从多核中受益,并且可以让CPU拥有的内核越来越快。
实际上像苹果和微软这样的公司已经计划如何让他们仍然是大多数单线程用户界面的多线程。即使采用上述方法,您可能有一天会遇到UI本身就是瓶颈的情况。后台进程可以比UI向用户呈现数据或者询问用户输入更快地处理数据。今天许多UI框架都是线程安全的,许多根本不是线程安全的,但这会改变。串行处理(一个接一个的任务)是一个垂死的设计,并行处理(一次完成许多任务)是未来的发展方向。只需看看图形适配器。即使是最现代的NVidia显卡也具有可怜的性能,如果你只看GPU的MHz / GHz处理速度。在3D计算方面,它如何能够击败CPU?简单:它不是一个接一个地计算一个多边形点或一个纹理像素,而是并行地计算它们中的许多(实际上是一堆同时),并且它达到了仍然使CPU哭的吞吐量。例如。 ATI X1900(也称为竞争对手)有48个着色器单元!
答案 2 :(得分:2)
我认为delayedresult
正是您所寻找的:
http://www.wxpython.org/docs/api/wx.lib.delayedresult-module.html
有关示例,请参阅wxpython演示。
答案 3 :(得分:1)
取决于应用程序的线程或进程。实际上,最好让GUI成为自己的程序,并在有工作要做时向其他程序发送异步调用。您仍然会在GUI中使用多个线程来监视结果,但如果正在完成的工作很复杂并且没有直接连接到GUI,它可以简化操作。
答案 4 :(得分:1)
主题 - 让我们使用一个简单的2层视图(GUI,应用程序逻辑)。
应用程序逻辑工作应该在一个单独的Python线程中完成。对于需要传播到GUI层的异步事件,请使用wx的事件系统发布自定义事件。发布wx事件是线程安全的,所以你可以想象从多个上下文中做到这一点。
在另一个方向工作(GUI输入事件触发应用程序逻辑),我发现最好是自定义事件系统。使用“队列”模块可以使用线程安全的方式来推送和弹出事件对象。然后,对于每个同步成员函数,将其与异步版本配对,将异步函数对象和参数推送到事件队列。
如果一次只能执行一个应用程序逻辑级操作,这种方法效果特别好。这种模型的好处是同步很简单 - 每个同步函数从头到尾依次在其自身的上下文中工作,而不用担心先发制人或手工编码的屈服。您不需要锁来保护您的关键部分。在函数结束时,将事件发布到GUI层,指示操作已完成。
您可以对此进行扩展以允许存在多个应用程序级别的线程,但同步的常见问题将重新出现。
编辑 - 忘了提到它的美妙之处在于可以将应用程序逻辑与GUI代码完全分离。如果您决定使用不同的框架或使用提供应用程序的命令行版本,模块化将有所帮助。为此,您需要一个由GUI层实现的中间事件调度程序(应用程序级别 - > GUI)。
答案 5 :(得分:0)
使用Qt / C ++ for Win32。
我们将主要工作单位划分为不同的流程。 GUI作为单独的进程运行,并且能够根据需要从“工作”进程命令/接收数据。在当今的多核心世界中运作良好。
答案 6 :(得分:0)
这个答案不适用于OP关于Python的问题,而是更多的元响应。
简单的方法是线程。但是,并非每个平台都有先发制人的线程(例如BREW,其他一些嵌入式系统)。如果可能的话,只需将工作分块并在IDLE事件处理程序中执行。
在BREW中使用线程的另一个问题是它不会清理C ++堆栈对象,所以如果你简单地杀掉线程就会很容易泄漏内存。
答案 7 :(得分:0)
我使用线程,因此GUI的主事件循环永远不会阻塞。
答案 8 :(得分:0)
对于某些类型的操作,使用单独的过程非常有意义。在当天,产生一个过程会产生很多开销。使用现代硬件,这种开销几乎不会成为屏幕上的昙花一现。如果您正在产生一个长时间运行的过程,则尤其如此。
一个(可论证的)优势是它比可能导致更易维护的代码的线程更简单的概念模型。它还可以使您的代码更容易测试,因为您可以编写执行这些外部过程的测试脚本,而无需涉及GUI。有些人甚至认为这是主要优势。
对于我曾经处理过的一些代码,从线程切换到单独的进程导致净代码超过5000行,同时使GUI响应更快,代码更易于维护和测试,同时提高总体整体表现。