为什么我在20%繁忙的机器上得到IPC延迟

我在一台拥有10个内核且运行47个ClientApp实例的机器上的IPC出现延迟,这些实例都与MasterApp通信。

我偶尔会遇到严重的延迟。 这是我的日志的一部分。 左边的DateTime是日志DateTime(高性能记录器)。 []中的DateTimes是从MasterApp发送消息的时间。 每条消息都以@结尾。

所以第一条消息仅落后1毫秒,但最后消息落后71毫秒。

任何可能导致这种情况的想法以及我可以做些什么来消除延迟

20141030T120401.015 [--------*MD|USD/JPY 109.032 109.034 1000000.00 1000000.00 20141030T120401014@] 20141030T120401.084 [--------*MD|EUR/CHF 1.20580 1.20588 3000000.00 2000000.00 20141030T120401019@] 20141030T120401.163 [--------*MD|USD/JPY 109.031 109.034 1000000.00 1000000.00 20141030T120401088@*MD|EUR/CHF 1.20580 1.20588 3000000.00 1000000.00 20141030T120401092@] 

代码摘录:

  public void Connect(int port) { IPAddress[] aryLocalAddr = null; String strHostName = ""; try { // NOTE: DNS lookups are nice and all but quite time consuming. strHostName = Dns.GetHostName(); IPHostEntry ipEntry = Dns.GetHostByName(strHostName); aryLocalAddr = ipEntry.AddressList; } catch (Exception ex) { OutputWriteLine("Error trying to get local address: " + ex.Message); } socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.Blocking = false; IPEndPoint epServer = new IPEndPoint(aryLocalAddr[0], port); socket.BeginConnect(epServer, new AsyncCallback(ConnectCallBack), socket); } public void ConnectCallBack(IAsyncResult ar) { Socket socket = (Socket)ar.AsyncState; NewConnection(socket); } public void NewConnection(Socket socket) { Connection mc = new Connection(socket); connections.Add(mc); //OutputWriteLine("Client " + mc.SessionID() + " joined"); DateTime now = DateTime.Now; String intraMessage = "*IDENT|" + modelInitiatorApp.G.SLOTNAME; modelInitiatorApp.SetConnected(); SendMessage(mc, intraMessage); socket.BeginReceive(mc.stateObject.buffer, 0, mc.stateObject.buffer.Length, SocketFlags.None, new AsyncCallback(ReceivedCallBack), mc.stateObject); } public void ReceivedCallBack(IAsyncResult ar) { // StateObject state = (StateObject)ar.AsyncState; Socket socket = state.socket; try { int bytesRead = socket.EndReceive(ar); if (bytesRead > 0) { state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead)); OutputWriteLine("[--------"+state.sb.ToString()+"]"); string[] contents = state.sb.ToString().Split('@'); int delimCount = state.sb.ToString().Count(x => x == '@'); for (int d = 0; d < delimCount; d++) { if (contents[d] != "") OnMessage(state, contents[d]); } if (!state.sb.ToString().EndsWith("@")) { state.sb.Clear(); state.sb.Append(contents[contents.Count() - 1]); } else { state.sb.Clear(); } socket.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(ReceivedCallBack), state); } else { // If no data was received then the connection is probably dead OutputWriteLine("Client " + state.SessionID() + " disconnected"); socket.Shutdown(SocketShutdown.Both); socket.Close(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Unusual error during Receive!"); } } 

好吧我认为TCP在这里很好,我仍然相信在这种情况下你会在命名管道和本地套接字之间有类似的性能(我会非常有兴趣看到基准测试)。 我注意到的一件事是你的ReceivedCallback正在调用EndReceive,然后在再次调用BeginReceive之前做了很多工作。 这意味着您仍然可以在套接字上接收数据(很可能因为localhost上没有延迟),但您实际上并没有处理它。 你应该考虑使用socket.BeginReceive()是EndReceive()之后的第一个调用(并检查错误,连接关闭等),这样你在处理数据时就没有任何堆叠了。 显然你需要首先复制缓冲区或使用缓冲池(我个人使用缓冲池),这样你就不会破坏你的数据,但没有挂起的BeginReceive()调用并坐在那里处理数据会增加一些人工延迟,因为你很快就得到了数据,但你只是忽略了它。 我已经看到这种类型的事情发生在Web对象之前,其中回调处理非常大的对象的反序列化,所以如果在这种情况下我就不会感到惊讶。 我会说你应该尝试下一件事,看看是否会改变延迟。 完全有可能我不正确但我认为重构你的代码就像我在这里推荐的那样值得你花时间看看它是否解决了这个问题。

这里有很多错误。

首先,TCP。 没有什么能比TCP,但它不是每个默认的低延迟ant完全是一台机器上的任何东西的错误技术。

切换到命名管道 – 将使用引擎盖下的共享内存。 您还可以在同一台计算机上删除任何查找。

http://msdn.microsoft.com/en-us/library/bb546085(v=vs.110).aspx

有示例代码。 正确编码,你可以接近RAM的速度。

也就是说,你也不应该发送文本 – 梦想一些二进制编码或者你浪费时间编码和解码。

您不应该使用DateTime来对性能进行基准测试,因为它不准确。

http://blogs.msdn.com/b/ericlippert/archive/2010/04/08/precision-and-accuracy-of-datetime.aspx

如果您想问的问题是某些操作需要多长时间,并且您需要高精度,高精度的答案,那么请使用StopWatch类。 它确实具有接近其精度的纳秒精度和精度。

请记住,您不需要知道知道已经过了多长时间的时间。 这些可以完全是两件事。