Я соединяю 15 асинхронных операций через порты и приемники. Это меня очень беспокоило время межсетевого обмена сообщениями, в частности время, затрачиваемое на перенос данных задачи на порт, и новая задача начинает обрабатывать эти же данные в другом потоке. Предполагая, что в начале каждого случая каждый поток неактивен, я создал тест, который использует класс секундомера для измерения времени от двух разных диспетчеров, каждый из которых работает с наивысшим приоритетом одним потоком.Время межпотоковой связи
Что меня удивило, моя установка для разработки - это Q6600 Quad Core 2.4 Ghz, работающий под управлением Windows 7 x64, а среднее время переключения контекста из моего теста составляло 5,66 микросекунды со стандартным отклонением 5,738 микросекунды и максимум почти 1,58 миллисекунды (в 282 раза!). Частота секундомера составляет 427,7 наносекунды, поэтому я все еще не чувствую шума датчика.
Что бы я хотел сделать, это сократить максимально возможное время обмена сообщениями и, что не менее важно, уменьшить стандартное отклонение контекстного переключателя. Я понимаю, что Windows не является оперативной оперативной системой, и нет гарантий, но планировщик окон - это график с честным круговым распределением по приоритетам, и два потока в этом тесте оба имеют наивысший приоритет (единственные потоки, которые должны быть такими high), поэтому не должно быть каких-либо контекстных переключателей на потоках (очевидно, что максимальное время на 1,58 мс ... Я считаю, что кванты окон составляют 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();
}
}
}
Почему вы говорите «не должно быть каких-либо контекстных переключателей на потоках»? Единственный способ, каким я могу это сделать, - это если вы каким-то образом гарантируете использование потока в ядре. Из моего краткого прочтения документов CCR я не заметил никакой возможности, которая делает это. – sipwiz
Вы правы - это не гарантируется, но работает с наивысшим приоритетом, единственное, что может прервать поток, - это прерывание ядра или другой процесс, выполняющийся с наивысшим приоритетом (чего не должно было быть) ... – Superman
Вы не можете явно изменить стандартное отклонение переключателя контекста. Это зависит от слишком многих факторов. И ядро также будет использовать процессор вместе с другими процессами. – user224579