挂起能精确到1毫秒以下吗?

BATTLERxANGE 2009-10-30 06:38:37
现在执行一个操作,要在0.X毫秒以后在执行另外一个操作,比如我现在输入一个A,然后要在0.X毫秒以后在输出一个B
这个0.X毫秒有办法精确到吗?thread.sleep(1)是不行的,这个误差有10-15MS左右!
我现在的临时办法是使用一个空循环:for (int i = 0; i < 60000; i++) { }。这样大概不到1毫秒的延迟,但是这样会吃光CPU,CPU直接彪到100%,所以是肯定不可取的!
那么还有什么好的办法吗?希望试过了确实可行的朋友指教一二!
...全文
993 74 打赏 收藏 转发到动态 举报
写回复
用AI写文章
74 条回复
切换为时间正序
请发表友善的回复…
发表回复
gbb21 2010-07-25
  • 打赏
  • 举报
回复
[Quote=引用 68 楼 battlerxange 的回复:]

谢谢各位,现在用li45214521和ChrisAK所提供的多媒体计时的timeSetEvent,效果比较好,精确率也很不错!至于SLEEP误差应该在10MS左右的!因为使用timeSetEvent设置1MS周期的速度是SLEEP(1)的10倍左右!
但现在一个问题是不知道为什么还是有点不稳定,之前因为CPU100%不稳定能理解但现在却还是如此!
64L所说的确实有道理,但现在我将参数fuE……
[/Quote]
windows不是实时系统,不提供实时调度。
yiranlandtour1 2010-06-25
  • 打赏
  • 举报
回复
恩,喵喵
天乐 2009-11-01
  • 打赏
  • 举报
回复
这个在C#中是个很有趣的问题,关注一下
BATTLERxANGE 2009-10-31
  • 打赏
  • 举报
回复
使用了timeSetEvent这个后效果确实不错,CPU也很稳定几乎没有占用~但还是有点不稳定,灯有点小的闪烁偶尔有大的闪烁!
li45214521能在指点一二吗?
li45214521 2009-10-31
  • 打赏
  • 举报
回复
当然你可以在定时器中加入for循环,在for循环的前后执行你想要的结果
这样就可以把1ms分割成更小的执行周期,
不过,你用的for循环并不正确,因为不同的处理器频率不同for循环的时间不同,你应需要查询指令执行周期,然后才能延时你想要的时间,这个内容可以参考,编程之美中的部分内容.
showjim 2009-10-31
  • 打赏
  • 举报
回复
试试把for循环改成不耗CPU的操作(如读写硬盘)
Thr21ough 2009-10-31
  • 打赏
  • 举报
回复
最小应该是毫秒~
BATTLERxANGE 2009-10-31
  • 打赏
  • 举报
回复
谢谢各位,现在用li45214521和ChrisAK所提供的多媒体计时的timeSetEvent,效果比较好,精确率也很不错!至于SLEEP误差应该在10MS左右的!因为使用timeSetEvent设置1MS周期的速度是SLEEP(1)的10倍左右!
但现在一个问题是不知道为什么还是有点不稳定,之前因为CPU100%不稳定能理解但现在却还是如此!
64L所说的确实有道理,但现在我将参数fuEvent设为0即代表只执行一次,回调函数也是一个空方法,只有一行代码,即调用我需要间隔1MS后继续运行的方法。所以应该不会是timeSetEvent的问题吧?我个人是这么认为的!
考虑如下代码:

private delegate void TimeProc(uint id, uint msg, int user, int dw1, int dw2);
[DllImport("Winmm.dll")]
private extern static int timeSetEvent(uint delay, uint resolution, TimeProc timeProc, int user, uint fuEvent);
public void fangfa1()
{
//xxx.....
timeSetEvent(1, 1,new TimeProc(fangfa2), 0, 0);
}
public void fangfa2()
{
fangfa3();
}
public void fangfa3()
{
//xxx.....
}
jodem 2009-10-31
  • 打赏
  • 举报
回复
不能的
BATTLERxANGE 2009-10-31
  • 打赏
  • 举报
回复
38L的多媒体定时器能在详细一点吗?麻烦了!
BATTLERxANGE 2009-10-31
  • 打赏
  • 举报
回复
谢谢回复,但我已经说了很多遍了,请你们不要在纠结于“1毫秒以下”了!问题现在是1毫秒都达不到!别说1毫秒,5毫秒总可以吧?也无法达到呢!
回43楼:用QueryPerformanceCounter看的话大概是0。0002秒吧,不记得了
我先试试38L的方法!
其实只要能达到4-5毫秒的延迟并且不吃CPU就没问题了!
悔说话的哑巴 2009-10-31
  • 打赏
  • 举报
回复
你这个就只能做到WINDOWS默认的那种了
li45214521 2009-10-31
  • 打赏
  • 举报
回复
多媒体1ms波动比较大,4-5ms波动比较小
mengde007 2009-10-31
  • 打赏
  • 举报
回复
C#执行本来就不怎么快;想精确1ms不可能;
li45214521 2009-10-31
  • 打赏
  • 举报
回复
多媒体定时器不稳定是你的代码在执行的过程中,执行了超过1ms的周期,
在多媒体回叫函数中调用API都有很强的限制,这种限制就是为了你的执行周期不要超过1ms
,所以我开始就说,在开始就需要缓冲区.另外不要在定时器中调用界面控件的Invoke,需要调用界面控件的BeginInvoke(其实就是PostMessage).
限制:
Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugString.
yizhili 2009-10-31
  • 打赏
  • 举报
回复
[Quote=引用 61 楼 hack95 的回复:]
传说可以通过CPU主频的震动次数来精确把握时间,没试过。
[/Quote]

QueryPerformanceCounter 就是用来获得 CPU 周期数的
lnwuyaowei 2009-10-31
  • 打赏
  • 举报
回复
学习了.
柳晛 2009-10-31
  • 打赏
  • 举报
回复
传说可以通过CPU主频的震动次数来精确把握时间,没试过。
darvei 2009-10-31
  • 打赏
  • 举报
回复
我现在的临时办法是使用一个空循环:for (int i = 0; i < 60000; i++) { }。这样大概不到1毫秒的延迟,但是这样会吃光CPU,CPU直接彪到100%,所以是肯定不可取的!

==

怎么看出来的?代码给分享下。

yizhili 2009-10-31
  • 打赏
  • 举报
回复
嗯,突然想起以前分析代码效率时的一个推测:即 sleep 的精度其实是在 1ms 的,但因为测量工具的问题(win32 的最简单的工具:GetTickCount 的精度是 15ms 左右),产生了 sleep 精度不高的误解
当时没有去实测过,所以今天写了段代码测试了下


public static void Test()
{
Console.WriteLine( Stopwatch.Frequency ); // 输出 CPU 频率

Stopwatch sw = new Stopwatch( );

sw.Start( );
int s = 0;
for( int i = 0; i < 60000; ++i ) // 测试 Stopwatch 精度
s += i;
sw.Stop( );
Console.WriteLine( sw.ElapsedMilliseconds );
Console.WriteLine( sw.ElapsedTicks );

sw.Reset( );
sw.Start( );
Thread.Sleep( 0 ); // 看看 Sleep(0) 花了多少时间
sw.Stop( );
Console.WriteLine( sw.ElapsedMilliseconds );
Console.WriteLine( sw.ElapsedTicks );

sw.Reset( );
sw.Start( );
Thread.Sleep( 1 ); // 看看 Sleep(1) 花了多少时间
sw.Stop( );
Console.WriteLine( sw.ElapsedMilliseconds );
Console.WriteLine( sw.ElapsedTicks );

sw.Reset( );
sw.Start( );
while( true ) // 使用 Sleep(0) 进行精度控制
{
if( sw.ElapsedMilliseconds >= 1 )
break;
Thread.Sleep( 0 );
}
sw.Stop( );
Console.WriteLine( sw.ElapsedMilliseconds );
Console.WriteLine( sw.ElapsedTicks );
}


结果是:

2793060000 // CPU 频率
0
668955 // Stopwatch 的精度还是可以的 ( << 1ms )
0
207879 // Sleep(0)的时间
1
4608485 // Sleep(1)的时间
1
2799734 // 用 Sleep(0) 控制时间

可以看到,Sleep(1)实际时间是 2ms 不到,用 Sleep(0) 可以比较精确的控制到 1ms
多次测量,除了 Sleep(0) 差异较大外,其他都保持在这个数量级
加载更多回复(52)
Date 对象属性constructor 返回对创建此对象的 Date 函数的引用。prototype 使您有能力向对象添加属性和方法。Date 对象方法getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)。getFullYear() 从 Date 对象以四位数字返回年份。getHours() 返回 Date 对象的小时 (0 ~ 23)。getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。getMonth() 从 Date 对象返回月份 (0 ~ 11)。getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。getTime() 返回 1970 年 1 月 1 日至今的毫秒数。getTimezoneOffset() 返回本地时间与格林威治标准时间 (GMT) 的分钟差。getUTCDate() 根据世界时从 Date 对象返回月中的一天 (1 ~ 31)。getUTCDay() 根据世界时从 Date 对象返回周中的一天 (0 ~ 6)。getUTCFullYear() 根据世界时从 Date 对象返回四位数的年份。getUTCHours() 根据世界时返回 Date 对象的小时 (0 ~ 23)。getUTCMilliseconds() 根据世界时返回 Date 对象的毫秒(0 ~ 999)。getUTCMinutes() 根据世界时返回 Date 对象的分钟 (0 ~ 59)。getUTCMonth() 根据世界时从 Date 对象返回月份 (0 ~ 11)。getUTCSeconds() 根据世界时返回 Date 对象的秒钟 (0 ~ 59)。getYear() 已废弃。 请使用 getFullYear() 方法代替。parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。setFullYear() 设置 Date 对象中的年份(四位数字)。setHours() 设置 Date 对象中的小时 (0 ~ 23)。setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。setMonth() 设置 Date 对象中月份 (0 ~ 11)。setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。setTime() setTime() 方法以毫秒设置 Date 对象。setUTCDate() 根据世界时设置 Date 对象中月份的一天 (1 ~ 31)。setUTCFullYear() 根据世界时设置 Date 对象中的年份(四位数字)。setUTCHours() 根据世界时设置 Date 对象中的小时 (0 ~ 23)。setUTCMilliseconds() 根据世界时设置 Date 对象中的毫秒 (0 ~ 999)。setUTCMinutes() 根据世界时设置 Date 对象中的分钟 (0 ~ 59)。setUTCMonth() 根据世界时设置 Date 对象中的月份 (0 ~ 11)。setUTCSeconds() setUTCSeconds() 方法用于根据世界时 (UTC) 设置指定时间的秒字段。setYear() 已废弃。请使用 setFullYear() 方法代替。toDateString() 把 Date 对象的日期部分转换为字符串。toGMTString() 已废弃。请使用 toUTCString() 方法代替。toISOString() 使用 ISO 标准返回字符串的日期格式。toJSON() 以 JSON 数据格式返回日期字符串。toLocaleDateString() 根据本地时间格式,把 Date 对象的日期部分转换为字符串。toLocaleTimeString() 根据本地时间格式,把 Date 对象的时间部分转换为字符串。toLocaleString() 据本地时间格式,把 Date 对象转换为字符串。toString() 把 Date 对象转换为字符串。toTimeString() 把 Date 对象的时间部分转换为字符串。toUTCString() 根据世界时,把 Date 对象转换为字符串。UTC() 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。valueOf() 返回 Date 对象的原始值。

110,552

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧