采用多线程方式模拟实时曲线,就两个线程,一个读数据线程,一个更新曲线线程。
Thread thread_GetDatabase = new Thread(GetDatabase);
thread_GetDatabase.Start();
Thread thread_updatechart = new Thread(UpdateChart);
thread_updatechart.Priority = ThreadPriority.Highest;
thread_updatechart.Start();
数据存放到共享队列中, 读数据线程写入队列, 更新曲线线程 从该队列读数据并显示。
private static ConcurrentQueue<double> _ConcurrentQueueBuffer { get; set; }
读数据库线程,循环读取, 间隔时间500毫秒
private void GetDatabase()
{
while (true)
{
GetDataFromOracle();
Thread.Sleep(500);
}
}
更新曲线线程,循环读取,间隔20毫秒
private void UpdateChart()
{
while(true)
{
update(); // 更新操作 更新操作的时间在0-1毫秒之间
Thread.Sleep(20);
}
}
问题: 长时间运行,更新曲线线程不能精确到20ms执行1次,大概1秒钟延迟2-3 毫秒,15分钟曲线延迟1秒钟,共享队列中的长度再逐步加大。随着时间推移,延迟越来越久,即取数据的线程的速度跟不上 读数据库的线程。
分析: 1. 可能 updatachart 线程的优先级有问题,后来设置为 highest优先级,还是一样。
2. 读数据线程 GetDatabase 线程 间隔500ms 太小,导致 CPU对updatchart 线程切换不能精确到20ms, 调整到1000ms,但是会出现共享队列的数据不够,曲线停顿的情况。
请问 如何保证 updatchart 线程精确到20ms 执行一次? 画图用的是WPF的livechart控件。
谢谢各位!
19 个解决方案
#1
这种帖子还是早结了吧,没有精确这一说,像你这种用Thread.Sleep的更没有什么精确度可言
#2
用Timer会精确很多,不过误差总是会存在。20ms绘制一次,是不是可以考虑从设计上去改造?
#3
楼主不明白:用线程定时=定时不准。再高级别线程也不行。(随便晃一下鼠标时间就漂了)。
想精确定时换其它定时器吧(windows下用户级别定时器精读理论上最多到1毫秒)。
想精确定时换其它定时器吧(windows下用户级别定时器精读理论上最多到1毫秒)。
#4
听说timers误差十几二十毫秒 sleep更是不确定了
#5
请问如何更精确呢?谢谢 。
#6
如果能从 采集软件直接读,我当然不会用这种方法,现在情况是只能读数据库,模拟曲线。
请问如何从设计考虑?谢谢
#7
不用windows 平台 ,用啥呢?
#8
windows下,推荐楼主用多媒体定时器,精度5毫秒以下,具体用法百度即可。
#9
我记忆里初中生就应该明白一个点可以用(x,y)表示
然而……ConcurrentQueue<double>
请问楼主什么学历?
然而……ConcurrentQueue<double>
请问楼主什么学历?
#10
那用timer还是会延迟啊,如何解决呢?谢谢
#11
不才,没你学历高。
时间信息,是利用系统时间累加的。数据库中偶尔有数据缺失,不能让曲线看起来不连贯。
清楚了没,博士?
#12
可以画成贝塞尔曲线,就连贯了
#13
厉害,几阶的?
#14
不使用 Thread.Sleep,线程一旦挂起,再次运行的时间就不由你控制了
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
#15
好好的技术帖 怎么说说就变成了装B帖了?
#16
我仔细读了两边才明白他的意思,他的疑问可能是一个点用x,y表示,应该是2个整形,但他没有弄懂你为什么用一个double,
ConcurrentQueue<double>
#17
你才延迟即毫秒 庆幸了吧你。。
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
#18
Window系统本身就不是一个实时的操作系统!
#19
你才延迟即毫秒 庆幸了吧你。。
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
谢谢,关键还是windwos 的调度机制不是实时的
#20
#1
这种帖子还是早结了吧,没有精确这一说,像你这种用Thread.Sleep的更没有什么精确度可言
#2
用Timer会精确很多,不过误差总是会存在。20ms绘制一次,是不是可以考虑从设计上去改造?
#3
楼主不明白:用线程定时=定时不准。再高级别线程也不行。(随便晃一下鼠标时间就漂了)。
想精确定时换其它定时器吧(windows下用户级别定时器精读理论上最多到1毫秒)。
想精确定时换其它定时器吧(windows下用户级别定时器精读理论上最多到1毫秒)。
#4
听说timers误差十几二十毫秒 sleep更是不确定了
#5
这种帖子还是早结了吧,没有精确这一说,像你这种用Thread.Sleep的更没有什么精确度可言
请问如何更精确呢?谢谢 。
#6
用Timer会精确很多,不过误差总是会存在。20ms绘制一次,是不是可以考虑从设计上去改造?
如果能从 采集软件直接读,我当然不会用这种方法,现在情况是只能读数据库,模拟曲线。
请问如何从设计考虑?谢谢
#7
楼主不明白:用线程定时=定时不准。再高级别线程也不行。(随便晃一下鼠标时间就漂了)。
想精确定时换其它定时器吧(windows下用户级别定时器精读理论上最多到1毫秒)。
不用windows 平台 ,用啥呢?
#8
windows下,推荐楼主用多媒体定时器,精度5毫秒以下,具体用法百度即可。
#9
我记忆里初中生就应该明白一个点可以用(x,y)表示
然而……ConcurrentQueue<double>
请问楼主什么学历?
然而……ConcurrentQueue<double>
请问楼主什么学历?
#10
听说timers误差十几二十毫秒 sleep更是不确定了
那用timer还是会延迟啊,如何解决呢?谢谢
#11
我记忆里初中生就应该明白一个点可以用(x,y)表示
然而……ConcurrentQueue<double>
请问楼主什么学历?
不才,没你学历高。
时间信息,是利用系统时间累加的。数据库中偶尔有数据缺失,不能让曲线看起来不连贯。
清楚了没,博士?
#12
可以画成贝塞尔曲线,就连贯了
#13
可以画成贝塞尔曲线,就连贯了
厉害,几阶的?
#14
不使用 Thread.Sleep,线程一旦挂起,再次运行的时间就不由你控制了
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
#15
好好的技术帖 怎么说说就变成了装B帖了?
#16
我记忆里初中生就应该明白一个点可以用(x,y)表示
然而……ConcurrentQueue<double>
请问楼主什么学历?
不才,没你学历高。
时间信息,是利用系统时间累加的。数据库中偶尔有数据缺失,不能让曲线看起来不连贯。
清楚了没,博士?
我仔细读了两边才明白他的意思,他的疑问可能是一个点用x,y表示,应该是2个整形,但他没有弄懂你为什么用一个double,
ConcurrentQueue<double>
#17
你才延迟即毫秒 庆幸了吧你。。
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
#18
Window系统本身就不是一个实时的操作系统!
#19
你才延迟即毫秒 庆幸了吧你。。
windows默认10毫秒切换一次时间片 假设单核cpu下 电脑中一共10个线程 其中一个是你的 而且每个线程都需要占用大量的cpu时间 比如里面写上死循环 那么这种情况 每个线程都会把10毫秒用满 而轮询一圈时间片切换到你的线程的时候 已经过了90毫秒了 你觉得你里面的Sleep(20)有用?
当执行到你的Sleep的时候 那么系统认为你将放弃你所拥有的时间片 那么立即切换到其他线程去 一圈后回来 如果时间还没有到你的20毫秒 那么继续切放弃你的时间片 再回来的时候发现你的20毫秒已经到了 那么这个时候你的代码才会得到执行的机会 所以说你现在还觉得windows下面想要毫秒级别 还会准吗?尤其实在cpu使用率很高的情况下
有一种很不友好的很暴力的方式来 稍微提高一下精度就是:
时间 a = 当前时间;
while(当前时间 - a < 20毫秒){/*空循环把cpu的时间片占着 不要让他切走*/}
但是这样会让你的cpu使用率变高
但是上面的并不能解决你的问题 因为你只有10毫秒执行时间 结果你要执行20毫秒的空循环 所以时间片要到你两次才能把空循环执行完毕 还要等第三次时间片进入才能执行你真正想要执行的代码所以 你还白白浪费了20毫秒的cpu时间 如果说 你的延时比较小10毫秒内 那么到可以考虑一下上面的代码
谢谢,关键还是windwos 的调度机制不是实时的