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

时间:2014-10-30 12:58:03

标签: c# sockets asynchronous ipc latency

我在一台拥有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!");
            }
        }

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

这里有多处错误。

首先,TCP。没有什么可以抵御TCP,但它不是每个默认的低延迟,对于单个机器上的任何东西来说都是错误的技术。

切换到命名管道 - 将使用引擎盖下的共享内存。你也可以在同一台机器上摆脱任何查找。

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

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

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

答案 2 :(得分:0)

您不应该使用DateTime来衡量性能,因为它不准确。

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

  

如果您想问的问题是某些操作需要多长时间,   并且你想要一个高精度,高精度的答案,然后使用   StopWatch类。它确实具有纳秒精度和准确度   这接近它的精确度。

     

请记住,您不需要知道知道多少时间是什么时候   已经过去了。这些可能完全是两件事。