C# c语言中信令线程的性能#

C# c语言中信令线程的性能#,c#,performance,stopwatch,autoresetevent,C#,Performance,Stopwatch,Autoresetevent,我一直在试图了解“唤醒”一个正在等待阻塞构造(如AutoResetEvent)的线程需要多长时间——在阅读了多次讨论后,我了解到windows有某种内部时钟,它每15.6ms(或更高)一次“滴答”一声,然后决定下一步运行哪些线程,因此,我预计在给线程发信号直到该线程醒来之间的时间差将在0-15.6毫秒之间随机出现。 所以我写了这个小程序来测试我的理论: static void Main(string[] args) { double total = 0;

我一直在试图了解“唤醒”一个正在等待阻塞构造(如
AutoResetEvent
)的线程需要多长时间——在阅读了多次讨论后,我了解到windows有某种内部时钟,它每15.6ms(或更高)一次“滴答”一声,然后决定下一步运行哪些线程,因此,我预计在给线程发信号直到该线程醒来之间的时间差将在0-15.6毫秒之间随机出现。 所以我写了这个小程序来测试我的理论:

static void Main(string[] args)
        {
            double total = 0;
            int max = 100;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < max; i++)
            {                
                AutoResetEvent eventHandle = new AutoResetEvent(false);
                double time1 = 0;
                double time2 = 0;
                Thread t1 = new Thread(new ThreadStart(() => time1 = f1(stopwatch, eventHandle)));
                Thread t2 = new Thread(new ThreadStart(() => time2 = f2(stopwatch, eventHandle)));
                t1.Start();
                t2.Start();
                t1.Join();
                t2.Join();
                double diff = time2 - time1;
                total += diff;
                Console.WriteLine("Diff = " + diff.ToString("F4"));
            }
            double avg = total / max;
            Console.WriteLine("Avg = " + avg.ToString("F4"));

            Console.ReadKey();
        }

        static double f1(Stopwatch s, AutoResetEvent eventHandle)
        {
            Thread.Sleep(500);
            double res = s.Elapsed.TotalMilliseconds;
            eventHandle.Set();
            return res;
        }

        static double f2(Stopwatch s, AutoResetEvent eventHandle)
        {
            eventHandle.WaitOne();
            return s.Elapsed.TotalMilliseconds;                        
        }
static void Main(字符串[]args)
{
双倍合计=0;
int max=100;
秒表秒表=新秒表();
秒表。开始();
对于(int i=0;itime1=f1(秒表、事件句柄));
线程t2=新线程(新线程开始(()=>time2=f2(秒表、事件句柄));
t1.Start();
t2.Start();
t1.Join();
t2.连接();
双差=时间2-时间1;
总+=差异;
Console.WriteLine(“Diff=”+Diff.ToString(“F4”);
}
双平均值=总/最大值;
Console.WriteLine(“Avg=”+Avg.ToString(“F4”);
Console.ReadKey();
}
静态双f1(秒表s、自动复位事件句柄)
{
睡眠(500);
double res=s.eassed.total毫秒;
eventHandle.Set();
返回res;
}
静态双f2(秒表s、自动复位事件句柄)
{
eventHandle.WaitOne();
返回s.eassed.total毫秒;
}

令我惊讶的是,平均唤醒时间约为0.05毫秒,所以很明显我遗漏了一些东西,但我不知道是什么…

不,15.625毫秒是时钟滴答声中断的时间。如果一个线程一直在运行而没有阻塞,那么调度程序就可以中断该线程,并且调度程序决定另一个线程应该轮到它

阻塞的线程将在其WaitXxx()调用时被抢占。或Sleep()调用。不管时钟滴答声中断


同样值得注意的是,睡眠线程只能在时钟中断时恢复运行,这就是thread.Sleep(1)实际上睡眠15.6毫秒的原因。计时器、DateTime.Now和Environment.TickCount也有这种精度,时钟会随着中断而增加。

我以前没有听说过内部时钟每15.6毫秒滴答一次,但你确定它不是一个更小的单位吗?谢谢Hans。还有一件事我不明白——当我执行
eventHandle.Set()
操作系统“立即”(几微秒后)唤醒该线程并开始运行它而不需要时钟?我认为上下文切换只能发生在“tick”函数内部。是的,它以这种方式工作非常重要。如果不这样做,线程将非常糟糕。类似EventWaitHandle.Set()的方法由CLR内部实现为操作系统调用SetEvent()。这将唤醒线程计划程序以取消阻止正在等待事件的线程。