实时图表性能问题 c# winform
Real Time chart performance issue c# winform
我目前正在使用 liveChart 绘制 3 个值的实时图表:位置、负载和变形。该程序基于 Doli.DoPE 库(专有 dll)
在MainForm.cs
中,每当传感器记录一个新值(大约每毫秒)时都会触发一个事件。
public void Initialisation()
{
//...
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData)
//...
}
和
private int OnData(ref DoPE.OnData Data, object Parameter)
{
DoPE.Data Sample = Data.Data;
if (Data.DoPError == DoPE.ERR.NOERROR)
{
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 250 /*ms*/)
{
// Send the data from the ondata handler inside of a global list
ListData.time.Add(Sample.Time);
ListData.position.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S]);
ListData.load.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F]);
ListData.extend.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E]);
Thread ThForUpdateChart = new Thread(() =>
{
if (NewINstanceOfChart != null)
{ NewINstanceOfChart.UpdateValues(ListData.time.Last(), ListData.position.Last(),ListData.load.Last(), ListData.extend.Last()); }
});
ThForUpdateChart.Start();
LastTime = Time;
}
}
return 0;
}
函数 UpdateValues
是通过按钮单击事件在 MainForm 中调用的第二个表单 RealTimeChart.cs
的一部分:
private void btnGraph_Click(object sender, EventArgs e)
{
var thread = new Thread(() =>
{
NewINstanceOfChart = new RealTimeChart(ListData);
NewINstanceOfChart.Show();
});
thread.Start();
}
表格RealTimeCharts.cs
是这样初始化的:
public RealTimeChart(Globals ListData)
{
InitializeComponent();
//measures = ListData;
ListPosition = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListPosition.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.position[i]
});
}
ListLoad = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListLoad.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.load[i]
});
}
ListExtend = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListExtend.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.extend[i]
});
}
resultChart.Series.Add(new LineSeries
{
LineSmoothness = 0,
Values = ListPosition,
PointGeometrySize = 2,
StrokeThickness = 4
});
SetXAxisLimits();
}
UpdateValues
函数定义如下:
public void UpdateValues(double time, double position, double load, double extend)
{
measures.time.Add(time-measures.TareTime);
measures.position.Add(position);
measures.load.Add(load);
measures.extend.Add(extend);
UpdateEnabledSequencialPartToTrue();
}
public void UpdateEnabledSequencialPartToTrue()
{
if (this.InvokeRequired)
BeginInvoke(new System.Action(() => this.InternalUpdateEnabledSequencialPartToTrue()));
else
InternalUpdateEnabledSequencialPartToTrue();
}
private void InternalUpdateEnabledSequencialPartToTrue()
{
try
{
ListPosition.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.position.Last()
});
ListLoad.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.load.Last()
});
ListExtend.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.extend.Last()
});
//LineSeries plot = new LineSeries();
SetXAxisLimits();
// lets only use the last 14400 values (1h long recording, 14400 values at frequency of 1 record very 250ms, see OnData function MainForm
if (measures.time.Count > 14400)
{
ListPosition.RemoveAt(0);
ListLoad.RemoveAt(0);
ListExtend.RemoveAt(0);
}
}
catch (NullReferenceException) { }
}
一分钟后,程序开始变得非常卡顿。我尝试将第二个 winform (RealTimeCharts) 放在另一个线程上,这样 MainForm 就不会滞后(它正在驾驶一台机器,它必须响应),但没有成功。
我想知道整个事情是否因为代码太糟糕而变得迟缓,或者是否是 liveChart 达到了它的(免费)限制。您会建议另一种绘制实时数据的方法吗?
In MainForm.cs, there is an event that is triggered everytime the sensor records a new value (every millisecond or so).
这自然比 Winforms Drawing 所能达到的要高得多。看,绘制 GUI 很昂贵。如果您只对每个用户触发的事件执行一次,您将永远不会注意到这一点。但是从一个循环开始——包括每个 MS 采样一个传感器——你可以很快地控制 UI。我的第一个多线程测试实际上似乎在大数字上失败了,因为我最终 发送了如此多的更新 我简单地重载了 GUI 线程。从那以后我就知道不能越过进度条了。
您可以像对数据进行采样一样快地将数据添加到背景集合中,但绘制速度却不能那么快。老实说,比 30-60 times/second(每 ~17 毫秒)更频繁地绘制无论如何都不会真正帮助任何人。通常您不能使用计时器,因为 Tick 发生的频率可能比它可以处理的频率高 - 同样,GUI 线程的事件队列溢出。
我没有任何 WindowsForms 的速率限制代码。但我猜想在完成工作后在 EventQueue 的末尾重新排队的 Event 会起作用。
我目前正在使用 liveChart 绘制 3 个值的实时图表:位置、负载和变形。该程序基于 Doli.DoPE 库(专有 dll)
在MainForm.cs
中,每当传感器记录一个新值(大约每毫秒)时都会触发一个事件。
public void Initialisation()
{
//...
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData)
//...
}
和
private int OnData(ref DoPE.OnData Data, object Parameter)
{
DoPE.Data Sample = Data.Data;
if (Data.DoPError == DoPE.ERR.NOERROR)
{
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 250 /*ms*/)
{
// Send the data from the ondata handler inside of a global list
ListData.time.Add(Sample.Time);
ListData.position.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S]);
ListData.load.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F]);
ListData.extend.Add(Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E]);
Thread ThForUpdateChart = new Thread(() =>
{
if (NewINstanceOfChart != null)
{ NewINstanceOfChart.UpdateValues(ListData.time.Last(), ListData.position.Last(),ListData.load.Last(), ListData.extend.Last()); }
});
ThForUpdateChart.Start();
LastTime = Time;
}
}
return 0;
}
函数 UpdateValues
是通过按钮单击事件在 MainForm 中调用的第二个表单 RealTimeChart.cs
的一部分:
private void btnGraph_Click(object sender, EventArgs e)
{
var thread = new Thread(() =>
{
NewINstanceOfChart = new RealTimeChart(ListData);
NewINstanceOfChart.Show();
});
thread.Start();
}
表格RealTimeCharts.cs
是这样初始化的:
public RealTimeChart(Globals ListData)
{
InitializeComponent();
//measures = ListData;
ListPosition = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListPosition.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.position[i]
});
}
ListLoad = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListLoad.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.load[i]
});
}
ListExtend = new ChartValues<ObservablePoint>();
for (int i = 0; i < measures.load.Count(); i++)
{
ListExtend.Add(new ObservablePoint
{
X = measures.time[i],
Y = measures.extend[i]
});
}
resultChart.Series.Add(new LineSeries
{
LineSmoothness = 0,
Values = ListPosition,
PointGeometrySize = 2,
StrokeThickness = 4
});
SetXAxisLimits();
}
UpdateValues
函数定义如下:
public void UpdateValues(double time, double position, double load, double extend)
{
measures.time.Add(time-measures.TareTime);
measures.position.Add(position);
measures.load.Add(load);
measures.extend.Add(extend);
UpdateEnabledSequencialPartToTrue();
}
public void UpdateEnabledSequencialPartToTrue()
{
if (this.InvokeRequired)
BeginInvoke(new System.Action(() => this.InternalUpdateEnabledSequencialPartToTrue()));
else
InternalUpdateEnabledSequencialPartToTrue();
}
private void InternalUpdateEnabledSequencialPartToTrue()
{
try
{
ListPosition.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.position.Last()
});
ListLoad.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.load.Last()
});
ListExtend.Add(new ObservablePoint
{
X = measures.time.Last(),
Y = measures.extend.Last()
});
//LineSeries plot = new LineSeries();
SetXAxisLimits();
// lets only use the last 14400 values (1h long recording, 14400 values at frequency of 1 record very 250ms, see OnData function MainForm
if (measures.time.Count > 14400)
{
ListPosition.RemoveAt(0);
ListLoad.RemoveAt(0);
ListExtend.RemoveAt(0);
}
}
catch (NullReferenceException) { }
}
一分钟后,程序开始变得非常卡顿。我尝试将第二个 winform (RealTimeCharts) 放在另一个线程上,这样 MainForm 就不会滞后(它正在驾驶一台机器,它必须响应),但没有成功。
我想知道整个事情是否因为代码太糟糕而变得迟缓,或者是否是 liveChart 达到了它的(免费)限制。您会建议另一种绘制实时数据的方法吗?
In MainForm.cs, there is an event that is triggered everytime the sensor records a new value (every millisecond or so).
这自然比 Winforms Drawing 所能达到的要高得多。看,绘制 GUI 很昂贵。如果您只对每个用户触发的事件执行一次,您将永远不会注意到这一点。但是从一个循环开始——包括每个 MS 采样一个传感器——你可以很快地控制 UI。我的第一个多线程测试实际上似乎在大数字上失败了,因为我最终 发送了如此多的更新 我简单地重载了 GUI 线程。从那以后我就知道不能越过进度条了。
您可以像对数据进行采样一样快地将数据添加到背景集合中,但绘制速度却不能那么快。老实说,比 30-60 times/second(每 ~17 毫秒)更频繁地绘制无论如何都不会真正帮助任何人。通常您不能使用计时器,因为 Tick 发生的频率可能比它可以处理的频率高 - 同样,GUI 线程的事件队列溢出。
我没有任何 WindowsForms 的速率限制代码。但我猜想在完成工作后在 EventQueue 的末尾重新排队的 Event 会起作用。