0

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

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

做这个的最好方式是什么?

4

1 回答 1

4

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

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

对于第三个问题,第一个问题是:缩略图生成实际上是否受 CPU 限制?如果您花费更多时间从磁盘读取和写入图像,则可能不是,因此尝试并行化它是没有意义的。但是,让我们假设它是。

首先,如果你有 N 个内核,你需要一个 N 个线程池,或者如果主线程也有很多工作要做,则需要 N-1 个,或者可能是 2N 或 2N-1 之类的东西来权衡一些最好的 -情况下的性能,以获得一些最坏情况下的性能。

但是,如果该 CPU 工作是在 Python 中完成的,或者是在仍然拥有 Python GIL 的 C 扩展中完成的,那么这将无济于事,因为大多数时候,实际上只有一个线程会运行。

一种解决方案是从线程切换到进程,最好使用标准multiprocessing模块。它有内置的 API 来创建进程池,并通过简单的负载平衡将作业提交到池中。

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

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

除此之外,您所要做的只是工作规模。希望创建一个缩略图不是太大的工作——但如果它太小了,你可以将多个缩略图批处理成一个工作——或者更简单地说,查看multiprocessingAPI 并更改它在以下情况下批处理工作的方式负载均衡。

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

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

于 2012-12-12T00:33:54.330 回答