线程与并发#
此可视化图表展示了图像采集在 Python 应用程序中的工作原理。
- 图像采集运行在 pylon 内部的 原生(C++)线程 中。
- 您的 Python 代码从 缓冲区队列 中检索图像。
- 这种分离实现了异步采集。
在许多应用程序中,图像采集速度快于处理速度:
没有并发机制时:
- 缓冲区被填满。
- 帧被丢弃。
- 延迟增加。
基本执行模型#
单线程方法是图像采集流水线最简单的形式。
示例:
while camera.IsGrabbing():
with camera.RetrieveResult(5000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
process(image)
这具有以下缺点:
- 处理过程会阻塞采集。
- CPU 利用率低下
- 可扩展性受限
生产者-消费者模式(推荐)#
这是一种用于图像采集流水线的更为复杂的方法。
- Producer:采集线程抓取图像并将其推送到队列中。
- Consumer:工作线程独立处理图像。
使用自定义线程的示例实现#
信息
您可以使用 InstantCamera 提供的抓取循环线程(请参阅 grab_using_grab_loop_thread 示例)。此自定义实现仅用于演示目的。
import threading
import queue
from pypylon import pylon
def process(image):
print(image.shape)
image_queue = queue.Queue(maxsize=10)
# Producer thread
def grab_loop(camera):
while camera.IsGrabbing():
with camera.RetrieveResult(5000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
image_queue.put(image)
# Consumer thread
def process_loop():
while True:
image = image_queue.get()
process(image)
image_queue.task_done()
with pylon.InstantCamera(pylon.FirstFound) as camera:
camera.StartGrabbing()
grab_thread = threading.Thread(target=grab_loop, args=(camera,))
processing_thread = threading.Thread(target=process_loop)
grab_thread.start()
processing_thread.start()
grab_thread.join()
image_queue.join()
队列行为与背压#
策略:
- 增大队列大小。
- 手动丢弃帧。
- 使用
LatestImageOnly.
与抓取策略相结合#
LatestImageOnly:减少积压。OneByOne:确保完整性。
最佳实践:
线程安全性注意事项#
- 避免在没有锁的情况下共享可变数据。
- 在将图像传递给其他线程之前复制图像,例如通过使用
Array函数。 - 使用
queue.Queue以实现安全的通信。
CPU 利用率#
并行处理具有以下优势:
- 更好的 CPU 利用率
- 关注点分离
- 可扩展的架构
何时使用多线程#
在以下情况下使用线程:
- 处理速度慢于采集速度。
- 存在多个处理阶段。
- 需要实时响应能力。
在以下情况下避免使用线程:
- 处理开销可以忽略不计。
- 必须保持最低的系统复杂度。
高级模式(概述)#
多阶段流水线#
多阶段流水线将图像处理拆分为独立步骤,这些步骤可并发运行并通过队列交换数据。
多消费者设置#
概念流水线#
核心要点#
- 采集和处理应进行解耦。
- 使用生产者-消费者模式来提高可扩展性。
- 队列提供线程安全的通信。
- 多线程可以提升性能,但也会增加复杂性。