如何使用1个计时器排队并与另一个计时器一起出列

时间:2013-09-21 13:53:48

标签: c# .net wpf

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

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

我不太确定我应该使用什么时间器和队列组合来实现这一点。

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

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

我没有详细介绍所有细节:

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

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

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

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

我提到了用户界面的33毫秒,因为这些数据被输入到实时图表中。 33毫秒大约是30帧/秒......任何比这慢的东西都会失去一些平滑度。

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

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

感谢大家的帮助。

3 个答案:

答案 0 :(得分:1)

您可以使用一个DispatcherTimer将队列出列并将其发布到用户界面,将另一个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
        }
    }
}

答案 1 :(得分:1)

这些是非常严格的时间要求。我质疑UI更新的~33ms值。用户界面不应该以人类可以感知到的速度更快地进行更新,即使这样也可能有点过分。

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

Producer -> Processor -> UI

在我上面的原始插图中,Producer将执行生成消息和排队的步骤。处理器将监视此队列并执行与消息无关的UI处理。处理完成后,它将生成消息,其中包含更新UI线程所需的足够信息。此管道中的每个步骤都将在指定的线程上运行。我假设你确实需要两个不同的间隔(分别为4ms和33ms)。我建议你为UI添加第3个。轮询间隔可能是:

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

我故意使用波浪号(〜)来突出显示在.NET中很难实现较低的间隔时序这一事实。您可能偶尔会达到33毫秒,但使用BCL中内置的任何计时器,任意“ticks”群体的标准差将非常高。当然,4毫秒是不可能的。

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

请参阅Jim Mischel's answer here,了解您的一些选项。

答案 2 :(得分:0)

由于您正在处理UI,因此您可以使用几个DispatcherTimer而不是经典计时器。此计时器仅用于与UI交互,因此您的队列应该能够排队/出列而没有任何问题。