4

C#とDelphiの間のプロシージャ間通信に名前付きパイプを使用しています。C#はSystem.IO.Pipesパッケージを使用しますが、Delphiはを使用しLibby's pipes.pasます。残念ながら、通信はほとんど高性能です。プロファイリングにより、通信はランタイム全体の72%を占め、残りは計算に使用されることがわかりました。
リソースを消費する可能性のある問題を1つ見つけることができました。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 <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();

再接続には費用がかかると思いますが、完全にはわかりません。1つのデータフロー(約1/11 kb)には、合計130(11kbの場合はそれぞれ270ms)がかかります(送信と受信)。

私の質問は次のようになります
クライアントが書き込みを完了したことを通知するためにパイプを強制的に切断する必要がありますか?私の観察によると、これは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

Delphi(受信)

 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
4

3 に答える 3

2

多くの(手動の)プロファイリングの後、私は問題について2つの洞察を思いつきました。

  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   
                ));                          
于 2012-10-22T13:00:31.770 に答える
0

たぶん、IPCシグナリングに名前付きイベントを使用できます。これらがローカルの場合(TEvent.Create('local \ myserver');異なるセッション間でIPCを実行する必要がある場合(クライアントアプリやバックグラウンドWindowsサービスなど)、Win7などで正常に機能します。より多くの権限などが必要です(デフォルトのグローバル\ 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/)のような「プロファイラー」ではありませんか?

于 2012-10-16T12:45:11.457 に答える
0

そして、単純な改善は次のようになります。最初に送信するバイト数を送信し(受信者が期待できるデータ量を認識できるように)、次にデータを送信します

于 2012-10-16T12:53:42.423 に答える