2

我需要以大约 4 到 8 毫秒的间隔将项目排入队列。

另外,我的 UI 层需要以大约 33 毫秒的间隔从这些项目中出列、处理和显示信息(它可能在该间隔内多次出列)。

我不太确定应该使用 Timers 和 Queue 的哪种组合来使其正常工作。

我想我应该为队列使用 ConcurrentQueue 类,但是我应该为入队和出队使用什么计时器机制?

更新:我最终选择了 Brian Gideon 和 Alberto 的答案。

没有详细介绍这里是我所做的:

我将以下计时器用于我的 4ms 计时器和 33ms 计时器。(http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer

我的 4ms 计时器从高速摄像机读取数据,进行少量处理并将数据排入 ConcurrentQueue。

我的 33ms 计时器从队列中取出所有项目,对每个项目进行更多处理并将数据发送到另一个对象,该对象计算某个给定时间间隔内的滚动平均值。(队列用于管理滚动平均值。)

在 CompositionTarget.Rendering 事件中,我从滚动平均对象中获取值并将它们绘制在我的自定义折线图控件上。

我提到了 UI 的 33 毫秒,因为这些数据被输入到实时图表中。33ms 大约是 30 fps ......任何比这慢的东西和一些平滑度都会丢失。

我最终也使用了 ConccuentQueue。效果很好。

CPU受到了一点打击。我认为这是由于高性能计时器。

感谢大家的帮助。

4

3 回答 3

1

这些是一些非常严格的时间要求。我质疑 UI 更新的 ~33ms 值。UI 的更新速度不应该比人类感知它的速度更快,即便如此,这也可能是矫枉过正。

我会做的是使用生产者-消费者管道。

Producer -> Processor -> UI

在我上面的原始插图中,生产者将执行生成消息并将它们排队的步骤。处理器将监视此队列并对消息进行非 UI 相关的处理。处理完成后,它将生成包含更新 UI 线程所需信息的消息。此管道中的每个步骤都将在指定线程上运行。我假设您确实需要两个不同的时间间隔(分别为 4 毫秒和 33 毫秒)。我建议您为 UI 添加第三个。轮询间隔可能是:

~4ms -> ~33ms -> 500ms

我有意使用波浪号 (~) 来强调这样一个事实,即在 .NET 中很难实现较低的时间间隔。您可能偶尔会达到 33 毫秒,但是使用 BCL 中内置的任何计时器,任意“滴答声”群体的标准偏差都会非常高。而且,当然,4ms 是不可能的。

您将需要尝试多媒体计时器或其他 HPET(高性能事件计时器)机制。其中一些机制使用特殊硬件。如果你走这条路线,那么你可能会更接近那个 4 毫秒的目标。不过不要指望奇迹。CLR 将从一开始就对你不利(垃圾收集)。

在此处查看Jim Mischel 的回答,了解您的一些选择。

于 2013-09-25T19:19:48.843 回答
1

您可以将一个DispatcherTimer用于出列元素并将它们发布到 UI,然后将另一个Timer用于入队。

例如:

class Producer
{
    public readonly Timer timer;
    public ConcurrentQueue<int> Queue {get;private set;}

    Producer()
    {
        timer = new Timer(Callback, null, 0, 8);
        Queue = new Concurrent<int>();
    }

    private void Callback(object state)
    {
        Queue.Enqueue(123);
    }
}

class Consumer
{
    private readonly Producer producer;
    private readonly DispatcherTimer timer;

    Consumer(Producer p)
    {
        producer = p;
        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(33);
        timer.Tick += new EventHandler(dispatcherTimer_Tick);
        timer.Start();
    }

    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        int value;
        if(producer.Queue.TryDequeue(out value))
        {
            // Update your UI here
        }
    }
}
于 2013-09-21T15:37:37.290 回答
0

由于您正在处理 UI,因此您可以使用几个 DispatcherTimer 来代替经典计时器。此计时器仅用于与 UI 交互,因此您的队列应该能够毫无问题地入队/出队。

于 2013-09-21T14:01:14.890 回答