简体   繁体   English

C#动作vs.事件vs.队列性能

[英]C# Action vs. Event vs. Queue performance

I have a Camera class that produces very large images at a high FPS that require processing by a ImageProcessor class. 我有一个Camera类,可以以很高的FPS生成非常大的图像,需要ImageProcessor类进行处理。 I also have a WPF Control, my View, that displays this information. 我还有一个WPF控件,即View,它显示此信息。 I need each of these components needs to run on it's own thread so it doesn't lock up the processing. 我需要这些组件中的每一个都需要在其自己的线程上运行,以便它不会锁定处理。

Method 1) Camera has an Action<Image> ImageCreated that ImageProcessor subscribes to. 方法1)相机具有ImageProcessor订阅的Action<Image> ImageCreated ImageProcessor has an Action<Image, Foo> ImageCreated that contains an altered Image and Foo results for the View to show. ImageProcessor具有一个Action<Image, Foo> ImageCreated ,其中包含更改后的Image和Foo结果以供View显示。

Method 2) Camera has a threadsafe (using locks and monitors) ProducerConsumer to which it produces Images, and ImageProcessor waits and Consumes. 方法2)相机具有一个线程安全的(使用锁和监视器)ProducerConsumer,它向其生成图像,并且ImageProcessor等待并消耗。 Same story for the View. 视图的故事也一样。

Method 2 is nice because I can create and manage my own threads. 方法2很不错,因为我可以创建和管理自己的线程。

Method 1 is nice because I have have multiple ImageProcessors subscribed to the Camera class. 方法1很好,因为我有多个ImageProcessor订阅了Camera类。 But I'm not sure who's thread is doing the heavyweight work, or if Action is wasting time creating threads. 但是我不确定谁的线程在做重量级工作,或者Action是否在浪费时间创建线程。 Again these images come in many times per second. 这些图像再次每秒出现很多次。

I'm trying to get the images to my View as quickly as possible, without tying up processing or causing the View to lock up. 我试图尽快将图像添加到我的视图中,而不会占用处理量或导致视图锁定。

Thoughts? 思考?

Unless you do it yourself, using Method 1) does not introduce any multithreading. 除非您自己做,否则使用方法1)不会引入任何多线程。 Invoking an action (unless you call BeginInvoke ) does so synchronously, just like any normal method call. 就像任何常规方法调用一样,调用动作(除非您调用BeginInvoke )是同步进行的。

I would advocate Method 2). 我主张方法2)。 There is no need to tie it to one single consumer. 无需将其绑定到一个单一的消费者。 If you use this queue as a single point of contact between X cameras and Y processors, you've decoupled the cameras from the processors and could modify the value of X and Y independently. 如果将此队列用作X摄像机和Y处理器之间的单个接触点,则已将摄像机与处理器解耦,并且可以独立修改X和Y的值。

EDIT 编辑

At the risk of being accused of blog spam here, I remembered that I wrote a component that's similar (if not an exact match) for what you're looking for awhile ago. 冒着被指控为博客垃圾邮件的风险,我记得我写了一个与您不久前所寻找内容相似(如果不完全匹配)的组件。 See if this helps: 看看是否有帮助:

ProcessQueue ProcessQueue

The gist of it is that you provide the queue with a delegate that can process a single item--in your case, Image --in the constructor, then call Start . 要点是为队列提供一个委托,该委托可以在构造函数中处理单个项目(在您的情况下为Image ,然后调用Start As items are added to the queue using Enqueue , they're automatically dispatched to an appropriate thread and processed. 使用Enqueue将项目添加到队列时,它们会自动分派到适当的线程并进行处理。

For example, if you wanted to have the image move Camera->Processor->Writer (and have a variable number of each), then I would do something like this: 例如,如果您想让图像移动Camera-> Processor-> Writer(每个图像具有可变的数目),那么我将执行以下操作:

ProcessQueue<Foo> processorQueue = new ProcessQueue<Foo>(f => WriteFoo(f));
ProcessQueue<Image> cameraQueue = new ProcessQueue<Image>(i => processorQueue.Enqueue(ProcessImage(i)));

You could vary the number of threads in cameraQueue (which controls the image processing) and processorQueue (which controls writing to disk) by using SetThreadCount . 您可以使用cameraQueue来更改cameraQueue (控制图像处理)和processorQueue (控制磁盘写入)中的SetThreadCount

Once you've done that, you would just call cameraQueue.Enqueue(image) whenever a camera captured an image. 完成此操作后,只要相机捕获到图像,就只需调用cameraQueue.Enqueue(image)

Method one will not work - the Action<T> will executed on the thread that invoked it. 方法一将不起作用Action<T>将在调用它的线程上执行。 Although you should probably use events instead of plain delegates in scenarios like this. 尽管在这种情况下您可能应该使用事件而不是普通委托。

Method two is the way to go, but if possible you should use the new thread-safe collection of .NET 4.0 instead of doing the synchronization yourself - we all know how hard it is to get even the simplest multi-threaded code correct. 方法二是可行的方法,但是如果可能的话,您应该使用.NET 4.0的新线程安全集合而不是自己进行同步-我们都知道,即​​使最简单的多线程代码正确,也很难。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM