命名管道性能问题

ott*_*uit 5 c# delphi io named-pipes

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

德尔福(发送)

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
Run Code Online (Sandbox Code Playgroud)

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 <MAX_RECONNECT_ATTEMPTS> 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();
Run Code Online (Sandbox Code Playgroud)

尽管我猜重新连接的成本很高,但我并不完全确定。一个数据流(大约 1 / 11 kb)总共需要 130 毫秒(11kb 分别为 270 毫秒)(发送和接收)。

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

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

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
Run Code Online (Sandbox Code Playgroud)

德尔福(接收)

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

ott*_*uit 4

经过大量(手动)分析后,我对这个问题提出了两个见解:

  1. 利比的笛子是一头复杂的野兽。由于它似乎使用多线程并且在使用方面表现出奇怪的行为,因此手动使用 WinApi 毕竟更方便。此外,实际通信所采取的性能也有所提高。换句话说:在像这样的相对简单的 IPC 场景中,libby 的管道似乎比 WinApi 慢。
  2. 匿名管道/使用标准输出和标准输入似乎比命名管道更快。

然而,我必须补充一点,我仍然有点困惑,无法判断这是真的还是我在这里处理了错误的数字。

下面是 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   
                ));                          
Run Code Online (Sandbox Code Playgroud)