采用多线程方式模拟实时曲线,就两个线程,一个读数据线程,一个更新曲线线程。
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>![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eE1pNW5hV1k9.jpg?w=700&webp=1)
请问楼主什么学历?
然而……ConcurrentQueue<double>
![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eE1pNW5hV1k9.jpg?w=700&webp=1)
请问楼主什么学历?
#10
那用timer还是会延迟啊,如何解决呢?谢谢
#11
不才,没你学历高。
时间信息,是利用系统时间累加的。数据库中偶尔有数据缺失,不能让曲线看起来不连贯。
清楚了没,博士?
#12
可以画成贝塞尔曲线,就连贯了
#13
厉害,几阶的?
#14
不使用 Thread.Sleep,线程一旦挂起,再次运行的时间就不由你控制了
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
你可以直接侦听系统时钟,并加以适当矫正
人眼的视觉残留是 0.1 秒,你每秒 50 帧 的更新速度,绝对可以保证看不出细微差异
#15
好好的技术帖 怎么说说就变成了装B帖了?
#16
我仔细读了两边才明白他的意思,他的疑问可能是一个点用x,y表示,应该是2个整形,但他没有弄懂你为什么用一个double,
ConcurrentQueue<double>
#17
![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eExtZHBaZz09.jpg?w=700&webp=1)
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>![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eE1pNW5hV1k9.jpg?w=700&webp=1)
请问楼主什么学历?
然而……ConcurrentQueue<double>
![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eE1pNW5hV1k9.jpg?w=700&webp=1)
请问楼主什么学历?
#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
![多线程中线程执行时间严格控制到毫秒级 多线程中线程执行时间严格控制到毫秒级](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0hNNkx5OW1iM0oxYlM1amMyUnVMbTVsZEM5UWIybHVkRVp2Y25WdEwzVnBMM05qY21sd2RITXZZM05rYmk5UWJIVm5hVzR2TURBekwyMXZibXRsZVM4eExtZHBaZz09.jpg?w=700&webp=1)
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 的调度机制不是实时的