C# 线程间通信时间

C# 线程间通信时间,c#,messaging,ccr,C#,Messaging,Ccr,我通过端口和接收器将15个异步操作链接在一起。这让我非常关注线程间消息传递时间,特别是任务将数据发布到端口和新任务开始在不同线程上处理相同数据之间的时间。假设在最好的情况下,每个线程在开始时都是空闲的,我已经生成了一个测试,它使用stop watch类来测量两个不同调度器的时间,每个调度器使用一个线程以最高优先级运行 我的发现让我惊讶,我的开发平台是一台运行Windows7x64的Q6600四核2.4GHz计算机,测试的平均上下文切换时间为5.66微秒,标准偏差为5.738微秒,最大值接近1.5

我通过端口和接收器将15个异步操作链接在一起。这让我非常关注线程间消息传递时间,特别是任务将数据发布到端口和新任务开始在不同线程上处理相同数据之间的时间。假设在最好的情况下,每个线程在开始时都是空闲的,我已经生成了一个测试,它使用stop watch类来测量两个不同调度器的时间,每个调度器使用一个线程以最高优先级运行

我的发现让我惊讶,我的开发平台是一台运行Windows7x64的Q6600四核2.4GHz计算机,测试的平均上下文切换时间为5.66微秒,标准偏差为5.738微秒,最大值接近1.58毫秒(系数282!)。秒表的频率是427.7纳秒,所以我仍然远离传感器噪音

我想做的是尽可能减少线程间消息传递时间,同样重要的是,减少上下文切换的标准偏差。我意识到Windows不是实时操作系统,也没有保证,但Windows调度程序是一个基于公平循环优先级的调度程序,并且此测试中的两个线程都处于最高优先级(只有线程应该如此高),因此线程上不应该有任何上下文切换(最长的时间是1.58毫秒……我相信windows quanta是15.65毫秒?)我唯一能想到的是操作系统调用CCR用来在线程之间传递消息的锁定机制的时间变化

请告诉我是否有其他人测量过线程间消息传递时间,并对如何改进它有任何建议

以下是我测试的源代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Ccr.Core;

using System.Diagnostics;

namespace Test.CCR.TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Timer");
            var sw = new Stopwatch();
            sw.Start();

            var dispatcher = new Dispatcher(1, ThreadPriority.Highest, true, "My Thread Pool");
            var dispQueue = new DispatcherQueue("Disp Queue", dispatcher);

            var sDispatcher = new Dispatcher(1, ThreadPriority.Highest, true, "Second Dispatcher");
            var sDispQueue = new DispatcherQueue("Second Queue", sDispatcher);

            var legAPort = new Port<EmptyValue>();
            var legBPort = new Port<TimeSpan>();

            var distances = new List<double>();

            long totalTicks = 0;

            while (sw.Elapsed.TotalMilliseconds < 5000) ;

            int runCnt = 100000;
            int offset = 1000;

            Arbiter.Activate(dispQueue, Arbiter.Receive(true, legAPort, i =>
                                                                            {
                                                                                TimeSpan sTime = sw.Elapsed;
                                                                                legBPort.Post(sTime);
                                                                            }));
            Arbiter.Activate(sDispQueue, Arbiter.Receive(true, legBPort, i =>
                                                                             {
                                                                                 TimeSpan eTime = sw.Elapsed;
                                                                                 TimeSpan dt = eTime.Subtract(i);
                                                                                 //if (distances.Count == 0 || Math.Abs(distances[distances.Count - 1] - dt.TotalMilliseconds) / distances[distances.Count - 1] > 0.1)
                                                                                 distances.Add(dt.TotalMilliseconds);

                                                                                 if(distances.Count > offset)
                                                                                 Interlocked.Add(ref totalTicks,
                                                                                                 dt.Ticks);
                                                                                 if(distances.Count < runCnt)
                                                                                     legAPort.Post(EmptyValue.SharedInstance);
                                                                             }));


            //Thread.Sleep(100);
            legAPort.Post(EmptyValue.SharedInstance);

            Thread.Sleep(500);

            while (distances.Count < runCnt)
                Thread.Sleep(25);

            TimeSpan exTime = TimeSpan.FromTicks(totalTicks);
            double exMS = exTime.TotalMilliseconds / (runCnt - offset);

            Console.WriteLine("Exchange Time: {0} Stopwatch Resolution: {1}", exMS, Stopwatch.Frequency);

            using(var stw = new StreamWriter("test.csv"))
            {
                for(int ix=0; ix < distances.Count; ix++)
                {
                    stw.WriteLine("{0},{1}", ix, distances[ix]);
                }
                stw.Flush();
            }

            Console.ReadKey();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用系统线程;
使用Microsoft.Ccr.Core;
使用系统诊断;
命名空间Test.CCR.TestConsole
{
班级计划
{
静态void Main(字符串[]参数)
{
控制台写入线(“启动计时器”);
var sw=新秒表();
sw.Start();
var dispatcher=new dispatcher(1,ThreadPriority.Highest,true,“我的线程池”);
var dispQueue=new DispatcherQueue(“Disp Queue”,dispatcher);
var sDispatcher=新调度程序(1,ThreadPriority.Highest,true,“第二个调度程序”);
var sDispQueue=新的DispatcherQueue(“第二个队列”,sDispatcher);
var legAPort=新端口();
var legBPort=新端口();
var距离=新列表();
长总滴答数=0;
而(sw.eassed.total毫秒<5000);
int runCnt=100000;
整数偏移=1000;
Activate(dispQueue,Arbiter.Receive)(true,legAPort,i=>
{
时间跨度时间=经过的时间;
勒格波特邮政公司(sTime);
}));
Activate(sDispQueue,Arbiter.Receive)(true,legBPort,i=>
{
TimeSpan eTime=已用软件;
TimeSpan dt=时间减去(i);
//if(distance.Count==0 | | Math.Abs(distance[distance.Count-1]-dt.total毫秒)/distance[distance.Count-1]>0.1)
距离.相加(dt.总毫秒);
如果(距离.计数>偏移)
联锁。添加(参考totalTicks,
蜱虫);
if(distance.Count
ThreadPriority.Highest并不意味着只有线程调度程序本身具有更高的优先级。Win32 API具有更细粒度的线程优先级(),比最高优先级高出几个级别(IIRC Highest通常是可以运行的最高优先级的非管理员代码,管理员可以安排更高的优先级,就像任何硬件驱动程序/内核模式代码一样),因此不能保证它们不会被抢占

即使线程以最高优先级运行,如果其他线程持有高优先级线程所需的资源锁,windows也可以将其提升到其基本优先级之上