实时绘制几个图表,C#表格

时间:2014-03-15 12:25:41

标签: c# multithreading timer charts

我想从我的A / C的16个频道预览,我需要25-40Hz的刷新率(每25-40ms更新一次)。我做了一些线程和定时器的组合,但我只获得了最多4个图表的令人满意的性能。在扩展图表范围以刷新后,添加图表的帧速率约为0.5 / s。我申请了快线图。
 我应用了一个计时器,每隔20ms从A / C获取新数据。经过一些测试后,看起来添加一个单独的线程来处理每个图表,这个图表会在给定时间内休眠,然后更新图表效率不高(至少按照我这样做的方式)。
 所以问题是:如何有效地处理多个图表。
下面我将介绍代码中最重要的部分。

    System.Timers.Timer tim = new System.Timers.Timer(20);
    System.Threading.Thread[] t;
    int HighChan = 15;
    //button which runs the preview, executed once
    private void previewB_Click(object sender, EventArgs e)
    {                                            
        t = new System.Threading.Thread[HighChan + 1];
        for (int i = 0; i <HighChan+1; i++)
        {                    
            charts[i].Series.SuspendUpdates();
            //run a separate thread for each chart
            t[i] = new System.Threading.Thread(new ParameterizedThreadStart(updatePlot));
            t[i].Start(i);                    
        }

        //run timer to get new data with tim.interval                    
        tim.Stop();               
        tim.Elapsed += new ElapsedEventHandler(this.OnTimedEvent);           
        tim.Start();                                
    }

    ushort[] ADData_prev;
    //get new data from A/C every tim.interval
    private void OnTimedEvent(object sender, EventArgs e)
    {
        ADData_prev = getPrev();  //gets new data, array wit 16 fields
        // I also tried to suspend and resume threads t from this place but unsuccessfully
    }


    //update the chart with new data
    void updatePlot(object chart_info)
    {          
        int i = (int)chart_info;

        while(true)
        {
                //wait for new data to read
                Thread.CurrentThread.Join(20);

                charts[i].Invoke(new Action(delegate()
                { charts[i].ResetAutoValues(); }));

                // I skipped some conditions to make code clearer                              
                //remove old point and add new one
                charts[i].Invoke(new Action(delegate()
                {
                    charts[i].Series[0].Points.RemoveAt(0);
                    charts[i].Series[0].Points.AddY(ADData_prev[i]);
                }));                     

                charts[i].Invoke(new Action(delegate()
                {
                    charts[i].Series.ResumeUpdates();
                    charts[i].Series.Invalidate();
                    charts[i].Series.SuspendUpdates();
                }));

          }
    }

更新:
1.我已将updatePlot()的功能移到了计时器的onTimedEvent,所以现在它看起来像是:

    private void OnTimedEvent(object sender, EventArgs e)
    {
        ADData_prev = getPrev();  //gets new data, array wit 16 fields

        charts[0].Invoke(new Action(delegate()
        {

           for (int i = 0; i < HighChan + 1; i++)
           {
               //charts[i] stuff here
           }
        }
    }

2.我决定更改onTimedEvent中的bool变量,它允许绘制一次图表,每个计时器在updatePlot()中的while(true)循环中勾选:

    private void previewB_Click(object sender, EventArgs e)
    {                                            
        for (int i = 0; i <= HighChan; charts[i++].Series.SuspendUpdates()) ;
        t = new System.Threading.Thread(updatePlot);
        t.Start();

        //run timer to get new data with tim.interval                    
        tim.Stop();               
        tim.Elapsed += new ElapsedEventHandler(this.OnTimedEvent);           
        tim.Start();                                
    }

    bool entry = false;
    private void OnTimedEvent(object sender, EventArgs e)
    {
        ADData_prev = getPrev();  //gets new data, array wit 16 fields
        entry = true;            
    }

    void updatePlot()
    {
       while(true)
       {
          if(entry)
          {
               charts[0].Invoke(new Action(delegate()
               {
                  for (int i = 0; i < HighChan + 1; i++)
                  {
                     //charts[i] stuff here
                  }
               }
          entry = false;
          }
       }
    }

这些解决方案只取得了很小的改进。不幸的是,在这两种情况下,图表都没有足够快地刷新。另外,来自charts []阵列的前8个快速刷新,而后8个帧速率大约为0.5 Hz,对我来说,他们的行为方式并不相同,这是非常奇怪的。


更新2:

与第一篇文章一样,我需要每20-40分钟重绘一次图表。当我只绘制一个绘图时,我可以达到此帧速率,因此不需要数据采集时间(A / C在背景中工作,Fs = 1k Hz)。也许绑定队列到图表使它更快但不是很多。

我将更准确地描述我所进行的性能测试中发生的事情 因此,当我将nr(要刷新的图表数量)限制为6时,用ti(时间间隔)20ms更新它们,因此它们一次存储点数(np)= 50,它们都运行平稳。但是,当我将np更改为100时,只有图表1-4运行平稳,5表示非常慢,6表示停止。 当nr = 6,ti = 20,np = 250时,图表1-3运行smoothm而图表4-6运行速度为0.1fps。

当nr = 10,ti = 20,np = 50时,图表1-6的行为与nr = 6的情况相同,而图表7-8令人惊讶地运行平稳,9-10表示像1fps。 当nr = 10,ti = 20,np = 100时,图表1-6的行为与nr = 6的情况相同(因此只有图表1-3运行平滑),而图表7-8仍然运行平稳且9- 10就像0.1fps。

当nr = 16,ti = 20,np = 50时,图1-8的行为类似于nr = 10的情况,而其他8的情况类似于0.05fps或其他。

无论我使用哪种方法,单线程,多线程,单/多调用,队列绑定,Thread.Sleep(),Threed.CurrentThread.Join(),定时器,异步结果总是更不一样。老实说,我不知道为什么我无法在16条快速线图表上获得实时数据预览。
我很感激任何建议。

1 个答案:

答案 0 :(得分:1)

说实话,我不认为多线程会对你有所帮助。在一天结束时,最重要的操作将是图表的更新,无论如何必须在UI线程上完成。

我建议您有一个单独的线程,每20ms获取所有最新值,然后在UI上调用单个Invoke,在单个Action内一次更新所有图表。每次更新多次调用会导致严重的性能损失。