Python:wx中的可中断线程

时间:2012-12-11 23:57:57

标签: python multithreading user-interface wxpython

我的wx GUI显示缩略图,但生成起来很慢,所以:

  • 缩略图生成时程序应保持可用。
  • 切换到新文件夹应停止为旧文件夹生成缩略图。
  • 如果可能,缩略图生成应使用多个处理器。

这样做的最佳方式是什么?

1 个答案:

答案 0 :(得分:4)

将缩略图生成放在threading.Thread的后台线程中将解决您的第一个问题,使程序可用。

如果你想要一种中断它的方法,通常的方法是添加一个“停止”变量,后台线程经常检查(例如,每个缩略图一次),并且GUI线程设置何时想要停止它。理想情况下,您应该使用threading.Condition来保护它。 (在大多数情况下,这个条件实际上并不是必需的 - 同样的GIL阻止你的代码很好地并行化,也可以保护你免受某些竞争条件的影响。但是你不应该依赖它。)

对于第三个问题,第一个问题是:缩略图生成实际上是CPU绑定的吗?如果你花更多的时间从磁盘读取和写入图像,它可能不是,所以尝试并行化它是没有意义的。但是,我们假设它是。

首先,如果你有N个核心,你需要一个N个线程的池,如果主线程有很多工作需要,则需要N-1,或者可能需要2N或2N-1这样的东西来进行权衡最坏情况表现的最佳表现。

但是,如果该CPU工作是在Python中完成的,或者在C扩展中完成,但仍然保留Python GIL,这将无济于事,因为大多数情况下,这些线程中只有一个实际上正在运行。

对此的一个解决方案是从线程切换到进程,理想情况下使用标准multiprocessing模块。它具有内置的API来创建进程池,并通过简单的负载平衡将作业提交到池中。

使用进程的问题是您不再自动共享数据,因此“停止标志”将不起作用。您需要在共享内存中显式创建一个标志,或者使用管道或其他一些机制进行通信。 multiprocessing文档解释了执行此操作的各种方法。

可以实际上只是杀死子进程。但是,您可能不想这样做。首先,除非您仔细编写代码,否则可能会使缩略图缓存处于不一致状态,从而混淆代码的其余部分。此外,如果您希望在Windows上有效,那么创建子进程需要一些时间(不像“30分钟”或任何内容,但如果每次用户单击时重新创建池,则足以影响代码的感知响应性新文件夹),因此您可能希望在需要之前创建池,并在程序的整个生命周期内保留它。

除此之外,你必须做的就是工作规模。希望创建一个缩略图不是太大的工作 - 但如果它太小的工作,你可以将多个缩略图批处理到一个作业 - 或者更简单地,查看multiprocessing API并更改它在负载平衡时批量工作。

同时,如果你使用池解决方案(无论是线程还是进程),如果你的工作足够小,你可能不需要取消。只需排空工作队列 - 每个工作人员将完成现在正在处理的任何工作,但随后睡觉直到您获得更多工作。在退出时,请记住排空队列(然后可能加入池)。

要记住的最后一件事是,如果您成功生成缩略图的速度与计算机能够生成缩略图一样快,那么实际上可能会导致整个计算机 - 以及您的GUI - 变得迟钝且无响应。当您的代码实际受I / O限制并且您正在使用大部分磁盘带宽时,或者当您使用大量内存并触发交换抖动时,通常会出现这种情况,但如果您的代码确实受CPU限制,那么您就是因为你正在使用所有CPU而遇到问题,你可能想要使用少1个核心,或者考虑设置线程/进程优先级。