我在 PyQt5 中编写了一个应用程序/GUI,并希望存储大型图像(>5000 RGB 图像)
现在,我有一个函数,它使用cv2.imwrite存储每张图片,但这个过程需要很多时间。所以我在Stackoverflow中读到,我可以通过多处理来做到这一点。但我对python很陌生。
我的多处理代码:
def SaveImages(self):
jobs = []
for i in range(5):
p = multiprocessing.Process(target = self.SaveAllImages, args=self)
jobs.append(p)
p.start()
在函数中,保存所有图像是存储每帧图像的基本代码。如果我运行此代码 - 有一个错误:
p = multiprocessing.Process(target = SaveAllImages, args=self)
NameError: name 'SaveAllImages' is not defined
但是SaveAllImages是定义的:def SaveAllImages(self)
所以我的问题是:
为什么我变成了这个错误
如何实现非常简单的多处理来存储图像
您看到的错误是因为您调用的方法不存在,可能是因为它不是self
的一部分。
您可能会看到多线程比多处理更好的性能。多处理最适合 CPU 密集型任务,原因很简单,Python 对所有操作都使用全局锁。多处理是绕过此锁的黑客。它比线程更讨厌,除非绝对必要,否则最好避免使用它。
多线程对于您的用例来说可能已经足够了,它不会为新程序员带来很多陷阱。下面是一个使用 Python 3 的 Futures API 的工作示例设置,可以轻松扩展您的问题大小,只需在标记的位置添加您的参数和实际保存代码即可。
import concurrent.futures
# Save single image
def save_image(image_arg):
# your image save code goes here
print("Working on image {}...".format(image_arg))
return True
# max_workers specifies the number of threads. If None then use 5x your CPU count
with concurrent.futures.ThreadPoolExecutor(max_workers=None) as executor:
# Images we'll save. Depending on how you generate your images you might not
# want to materialize a list like this to avoid running out of memory.
image_args = ["image1", "image2", "image3"]
# Submit futures to the executor pool.
# Map each future back to the arguments used to create that future. That way
# if one fails we know which image it was that failed.
future_to_args = {executor.submit(save_image, image_arg): image_arg for image_arg in image_args}
# Images are being saved in worker threads. They will complete in any order.
for future in concurrent.futures.as_completed(future_to_args):
image_arg = future_to_args[future]
try:
result = future.result()
except Exception as exc:
print("Saving image {} generated an exception: {}".format(image_arg, exc))
else:
print("Image {} saved successfully.".format(image_arg))
如果您坚持使用多处理,只需使用ProcessPoolExecutor
即可。如果您还想并行生成图像,这可能是值得的。
ThreadPoolExecutor
或ProcessPoolExecutor
更好在很大程度上取决于其余工作负载是什么以及您如何构建它。尝试两者,看看哪个更适合您。请注意,多处理对工作线程之间的通信和共享状态施加了限制,因此我建议先尝试线程。
在尝试改进之前,您应该始终衡量绩效。
使用磁盘测试程序查看磁盘的最大持续写入吞吐量是多少。
然后使用性能监视程序检查程序生成的写入吞吐量(无多线程/处理)。 如果您的程序在大多数时候可以达到与测试程序相同的吞吐量,那么您几乎无能为力。
假设您使用的是普通硬盘,则提高写入性能的最佳方法是改用 SSD。