当前位置:编程学习 > C#/ASP.NET >>

C# 怎么实现精确延时

我写的延时函数是这样的,

public void Wait(int ms)
{
DateTime t=DateTime.Now;
for(int i=0;i<ms;i++)
{
TimeSpan ts=DateTime.Now-t;
if(ts.TotalMiniseconds>=ms)
{
return;
}
}
return;
}

我有很多线程在运行,当使用这个函数延时的时候,误差有几百毫秒的误差,请问有没有比较精确的延时方法啊? --------------------编程问答-------------------- 没人啊,搞不定就要失业了啊 --------------------编程问答-------------------- 据我所知好像没有特别精确的,不过还是帮你顶一下 --------------------编程问答--------------------   public void Wait(int ms)
        {
          var timeout =  DateTime.Now.AddMilliseconds(ms);
            while (true)
            {
                //业务处理



                if (DateTime.Now < timeout)
                {
                    //超时
                    return;
                }
            
            }
        } --------------------编程问答-------------------- --------------------编程问答-------------------- 我是很多个线程在同时运行,其中某个线程要延时N个ms后继续往下运行,但是这个延时不太精确往往会误差很大,系统没有在延时的时间时进入该线程继续运行
还没有解决,看样子要挂了哦 --------------------编程问答-------------------- 延时只要 Sleep 一句话就行了,搞个循环干嘛啊?烧热 CPU 毁坏女老板的电脑吗?

想要所谓的“精确”,请你进行 ring-0 级编程。

在windows应用程序上,误差一定会有至少几十毫秒。 --------------------编程问答-------------------- .net的Thread.Sleep已经可以精确到1ms了,非常准的。
若要微秒级有以下几个可以使用:
1.KeDelayExecutionThread
2.NdisMSleep
3.NdisStallExecution --------------------编程问答-------------------- 要精确,需要用RTOS。 --------------------编程问答-------------------- http://hi.baidu.com/ixldqpronmbeisq/item/ccc11c33d2faf1f1e6bb7afb --------------------编程问答--------------------
引用 7 楼 bigbaldy 的回复:
.net的Thread.Sleep已经可以精确到1ms了,非常准的。
若要微秒级有以下几个可以使用:
1.KeDelayExecutionThread
2.NdisMSleep
3.NdisStallExecution

你确定??? --------------------编程问答-------------------- M$ say 
The default timer resolution on Windows 7 is 15.6 milliseconds (ms). Some applications reduce this to 1 ms --------------------编程问答-------------------- windows不是实时操作系统,所以做不到精确。 --------------------编程问答--------------------
引用 10 楼 gengchenhui 的回复:
你确定???


确定,不信的话你可以自己试验的
--------------------编程问答--------------------
引用 13 楼 bigbaldy 的回复:
Quote: 引用 10 楼 gengchenhui 的回复:

你确定???


确定,不信的话你可以自己试验的

我记得看过一个帖子,说的是:windows系统的时间的,人家的时间片最少好像是1、2百毫秒,也就是说:1秒以下根本不可能精确!,你自己验证一下,写个简单程序,一直输出:DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")试试看。中间最小的间隔多少毫秒??? --------------------编程问答-------------------- 你可以绕过windows直接操作cpu中断达到飞秒级的精确时间定为。不过要低级语言来写,C#不支持。 --------------------编程问答--------------------
引用 14 楼 gengchenhui 的回复:
我记得看过一个帖子,说的是:windows系统的时间的,人家的时间片最少好像是1、2百毫秒,也就是说:1秒以下根本不可能精确!,你自己验证一下,写个简单程序,一直输出:DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")试试看。中间最小的间隔多少毫秒???


那就是胡说八道,windows是可以精确到1毫秒以下的,更别说秒了,你的那个例子根本就不用试,最小的间隔时间一定是0毫秒,然后某一次输出会出现差了1毫秒。我告诉你一个方法

Stopwatch sw=new Stopwatch();
sw.Start();
for(int i=0;i<1000;i++)
{
    Thread.Sleep(1);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds.ToString());

输出结果在win7 64bit系统,I7 2600的CPU下是完美的1000,或者998,1002等,反正前后误差小于5毫秒,这充分证明了Sleep(1)就是一毫秒,KeDelayExecutionThread我也做过测试,该函数精度是100纳秒,用它我在驱动里写了个微秒级延迟函数,然后用C#调用,重复1000次,用sw.ElapsedTicks*1000*1000/Stopwatch.Frequency计算最终耗时,答案接近1000,也就是说KeDelayExecutionThread起码达到了微秒级精度,不信的话你自己试验,你也许会说代码被编译器优化了,这个你可以看IL,没有做任何优化,如果你不相信Stopwatch类的准确性,你可以放大时间,例如重复10000次,用你手中的秒表计时,答案绝对是无限接近10秒的 --------------------编程问答-------------------- 输出结果在win7 64bit系统,I7 2600的CPU下是完美的1000,或者998,1002等
你自己说精确到1毫秒以下,然后又说误差小于5毫秒,这是什么情况??? --------------------编程问答--------------------
引用 17 楼 gengchenhui 的回复:
输出结果在win7 64bit系统,I7 2600的CPU下是完美的1000,或者998,1002等
你自己说精确到1毫秒以下,然后又说误差小于5毫秒,这是什么情况???

晕,循环了1000次你没看到?1000次Sleep(1)计时结果是1002,那么一次是多少?1002/1000=1.002毫秒,够精确了吧 --------------------编程问答-------------------- 可以将就用下StopWatcher,不过追求极致的话,应该还是一些硬件读取了·· --------------------编程问答--------------------
引用 18 楼 bigbaldy 的回复:
Quote: 引用 17 楼 gengchenhui 的回复:

输出结果在win7 64bit系统,I7 2600的CPU下是完美的1000,或者998,1002等
你自己说精确到1毫秒以下,然后又说误差小于5毫秒,这是什么情况???

晕,循环了1000次你没看到?1000次Sleep(1)计时结果是1002,那么一次是多少?1002/1000=1.002毫秒,够精确了吧

WIN的进程调度时间是几十ms,你如何能精确到1ms,sleep(1)是自愿放弃,要看当前剩余活动线程的数量来乘于时间片才能确定下次活动时间。 --------------------编程问答-------------------- 你这就是没有LOCK的原因。。你这段代码是被多个线程调用的,你不LOCK它 它的结果就是不正确的。 --------------------编程问答-------------------- 没想到这里回复的人没有一个说到这个关键点吗。多线程调用共享的资源是要考虑这个资源的安全性的。
当你前一个线程在读到你的减法 时,后一个线程已经改变了你参与做减法的原数值。明白了吗 --------------------编程问答--------------------
引用 6 楼 sp1234 的回复:
延时只要 Sleep 一句话就行了,搞个循环干嘛啊?烧热 CPU 毁坏女老板的电脑吗?

想要所谓的“精确”,请你进行 ring-0 级编程。

在windows应用程序上,误差一定会有至少几十毫秒。

--------------------编程问答--------------------
引用 18 楼 bigbaldy 的回复:
Quote: 引用 17 楼 gengchenhui 的回复:

输出结果在win7 64bit系统,I7 2600的CPU下是完美的1000,或者998,1002等
你自己说精确到1毫秒以下,然后又说误差小于5毫秒,这是什么情况???

晕,循环了1000次你没看到?1000次Sleep(1)计时结果是1002,那么一次是多少?1002/1000=1.002毫秒,够精确了吧
即使是这样,不够,误差仍大于1毫秒,就不是你说的1毫秒以下,况且,服务器也不会只放你一个hello world类的程序,是不可能那么小的,人家windows的时间片就不止那么小。。。 --------------------编程问答--------------------
引用 24 楼 gengchenhui 的回复:
晕,循环了1000次你没看到?1000次Sleep(1)计时结果是1002,那么一次是多少?1002/1000=1.002毫秒,够精确了吧
即使是这样,不够,误差仍大于1毫秒,就不是你说的1毫秒以下,况且,服务器也不会只放你一个hello world类的程序,是不可能那么小的,人家windows的时间片就不止那么小。。。

那个2微秒的误差是for循环的时间,这个东西你自己可以试验的,你知不知道1000次Sleep(1)出现不等于1000的概率是多少?那个1002基本是我做试验遇到过最大的值了,如果出现不等于1000的概率是100分之一,那么实际误差就是远小于(1002+99*1000)/(1000*100)-1=0.00002毫秒,即20纳秒,排除for循环本身时间,可以说Sleep(1)就是1毫秒没有任何误差,再者说,你还可以用KeDelayExecutionThread,参数单位是百纳秒级的,而且我说的函数都是不占用CPU时钟的,楼主的方法属于死循环方式是占用CPU时钟的,不占用CPU时钟的方法是不受你服务器启动了几个程序影响的 --------------------编程问答--------------------
引用 22 楼 iloli 的回复:
没想到这里回复的人没有一个说到这个关键点吗。多线程调用共享的资源是要考虑这个资源的安全性的。
当你前一个线程在读到你的减法 时,后一个线程已经改变了你参与做减法的原数值。明白了吗


不是没人看到,而是你没注意到楼主参与减法的原数值t是局部变量,前一个线程与后一个线程中调用这个函数有何关系? --------------------编程问答--------------------
引用 20 楼 xu56180825 的回复:
WIN的进程调度时间是几十ms,你如何能精确到1ms,sleep(1)是自愿放弃,要看当前剩余活动线程的数量来乘于时间片才能确定下次活动时间。


我也很纳闷,如果两个线程,一个是13毫秒延迟循环,一个是10毫秒延迟循环,时间片为15毫秒,那么线程1执行完一次循环后再过2毫秒就被线程2抢占,线程2又过了15毫秒后被线程1抢占,那么线程1两次循环的输出结果应该是一次13,一次15,13与10之间不存在公约数且13是质数,那么如果这两个线程无限期执行下去,只要时间片不是1毫秒,那么我下面的代码总会出现非13、15的值输出,可实际测试结果是从来没有输出,我不知道我对时间片的理解是否正确,但我的试验结果证明延时函数很准

new Thread(()=>
           {
            Stopwatch sw=new Stopwatch();
            while(true)
            {
            sw.Reset();
            sw.Start();
            Thread.Sleep(13);
            sw.Stop();
            if(sw.ElapsedMilliseconds!=13)
            {
            Console.WriteLine(sw.ElapsedMilliseconds);
            }
            }
           }).Start();
   new Thread(()=>
           {
            Stopwatch sw=new Stopwatch();
            while(true)
            {
            sw.Reset();
            sw.Start();
            Thread.Sleep(10);
            sw.Stop();
            if(sw.ElapsedMilliseconds!=10)
            {
            Console.WriteLine(sw.ElapsedMilliseconds);
            }
            }
           }).Start();
--------------------编程问答-------------------- 你调用Thread.Sleep(13)的时候是放弃时间片明白吗?你可以让程序循环1XXXXXXX次来模拟时间,但不能用Thread.Sleep(13)来模拟时间,因为系统中进程基本上都是SLEEP状态,所以你2个线程相互放弃并相互切换,所以你测试的很准。 --------------------编程问答--------------------
引用 28 楼 xu56180825 的回复:
你调用Thread.Sleep(13)的时候是放弃时间片明白吗?你可以让程序循环1XXXXXXX次来模拟时间,但不能用Thread.Sleep(13)来模拟时间,因为系统中进程基本上都是SLEEP状态,所以你2个线程相互放弃并相互切换,所以你测试的很准。


你的这个问题我想到过,我把thread.sleep(13)改为while(true)测试过,即线程2放弃时间片,但线程1没有,如果时间片是15ms,那么线程2的sleep(10)就应该是不准的,可结果还是准的 --------------------编程问答--------------------
引用 29 楼 bigbaldy 的回复:
Quote: 引用 28 楼 xu56180825 的回复:

你调用Thread.Sleep(13)的时候是放弃时间片明白吗?你可以让程序循环1XXXXXXX次来模拟时间,但不能用Thread.Sleep(13)来模拟时间,因为系统中进程基本上都是SLEEP状态,所以你2个线程相互放弃并相互切换,所以你测试的很准。


你的这个问题我想到过,我把thread.sleep(13)改为while(true)测试过,即线程2放弃时间片,但线程1没有,如果时间片是15ms,那么线程2的sleep(10)就应该是不准的,可结果还是准的


补充一句,32位系统的确是不准的,就一个线程,sleep(1)也有15ms左右,但64位全是准的,
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,