命名管道性能问题

我正在使用命名管道进行C#和Delphi之间的程序间通信。 C#使用System.IO.Pipes包,而Delphi使用Libby's pipes.pas 。 不幸的是,通信几乎都是高性能的:分析表明通信占整个运行时间的72%,其余的则用于计算。
我找到了一个可能占用资源的问题:如果我没有在Delphi中明确断开发送客户端的连接, C#根本就不会收到任何数据

delphi(发送)

 FClient1.Write(msg[1], Length(msg)); FClient1.FlushPipeBuffers; FClient1.WaitForReply(20); FClient1.Disconnect; // disconnect to signalize C# that the writing is finished FClient1.Connect; // connect again to prevent synchronization problems 

C#(接收)

 // Wait for a client to connect stc.pipeServer.WaitForConnection(); while (reconnect_attempts < MAX_RECONNECT_ATTEMPTS) // { string tmp = sr.ReadLine(); // if result is empty, try again for  times // so you can eliminate the chance that there's just a single empty request while (tmp != null)// && result != tmp) { tmp = sr.ReadLine(); result += tmp; } // sleep, increment reconnect, write debugging... } stc.pipeServer.Close(); 

虽然我猜重新连接很昂贵,但我并不完全确定。 一个数据流(大约1/11 kb)总共需要130个(11kb为270毫秒)(发送和接收)。

我的问题是
是否有必要强制断开管道以表明客户端已完成写入? 就我的观察而言, 只有在使用libby发送时才需要这样做 。 表现不佳还有其他可能的原因吗? 提前致谢。

另外,这里的发送和接收完成相反:

C#(发送)

  stc.pipeClient.Connect(); StreamWriter sw = new StreamWriter(stc.pipeClient); //sw.AutoFlush = true; sw.WriteLine(msg); sw.Flush(); stc.pipeClient.WaitForPipeDrain(); // waits for the other end to read all bytes // neither disconnect nor dispose 

delphi(接收)

  SetLength(S, Stream.Size); Stream.Read(S[1], Length(S)); FPipeBuffer := FPipeBuffer + S; { TODO 2 : switch case ID } // if the XML is complete, ie ends with the closing checksum if (IsFullMessage()) then begin // end reading, set flag FIsPipeReady := true; end 

经过大量(手动)分析后,我想出了两个关于这个问题的见解:

  1. 利比的管子是一头复杂的野兽。 由于它似乎使用多个线程并显示出与其使用有关的奇怪行为,因此手动使用WinApi更方便。 此外,实际通信所采取的性能提高了。 换句话说: 在这样一个相对简单的IPC场景中,libby的管道似乎比WinApi慢。
  2. 匿名管道/使用stdout和stdin似乎比命名管道更快。

但是,我必须补充一点,我仍然有点困惑,无法判断这是否属实,或者我在这里正在处理错误的数字。

这是一个简单的例子,说明Delphi中的WinApi实现如何:

 // setup pipes, you'll need one for each direction // init handles with 0 CreatePipe(ReadPipe1, // hReadpipe WritePipe1, // hWritePIpe @SecurityAttributes, // Security PIPE_SIZE) // Size // setup Startupinfo FillChar(StartupInfo, Sizeof(StartupInfo), 0); StartupInfo.cb := Sizeof(StartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; StartupInfo.hStdInput := ReadPipe1; StartupInfo.hStdOutput := WritePipe2; StartupInfo.wShowWindow := SW_HIDE; // CreateProcess [...] // read Win32Check( ReadFile( ReadPipe1, // source (@outputBuffer[1])^, // buffer-pointer PIPE_BUFFER_SIZE, // size bytesRead, // returns bytes actually read nil // overlapped on default )); // send Win32Check( WriteFile( WritePipe2, (@msg[1])^, // lpBuffer - workarround to avoid type cast NumberOfBytesToWrite, bytesWritten, // lpNumberOfBytesWritten nil // Overlapped )); 

也许您可以将命名事件用于IPC信令。 当Win7等本地化时,这些工作正常(TEvent.Create(’local \ myserver’);当你需要在不同的会话之间进行IPC(例如客户端应用程序和后台Windows服务)时,你需要更多权限等(默认全局\因UAC而无法在win7中使用?) 。http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devwin32/threadswaitingforatasktobecompleted_xml.html

例如:为每个连接创建一个事件(每个连接生成一个名称)。

或者看一下不同的IPC命名管道+事件实现: https : //micksmix.wordpress.com/2011/06/27/named-pipes-unit-for-delphi/

顺便说一下:你提到你使用过性能分析但是你不能说最需要花费多少时间? 你使用了什么样的分析? 不是像AQtime(http://smartbear.com/products/free-tools/aqtime-standard)或AsmProfiler(http://code.google.com/p/asmprofiler/)这样的“探查器”?

简单的改进可能是:首先发送要发送的字节数(因此接收方知道它可以预期多少数据)然后发送数据