この質問の前に、私は絶対にプロの C# プログラマーではなく、これまで私の小さなプログラムのほとんどを力ずくで進めてきたと言っておきましょう。
私は小さなWinFormsアプリケーションをいくつかのデバイスにSSHで接続し、tail -f
それぞれにログファイルを作成し、ログファイルに保存しながらテキストボックスにリアルタイム出力を表示することに取り組んでいます。現在は動作していますが、ロギング中に CPU の 30% 近くを占有しており、何か間違ったことをしていると確信しています。
を作成しSshClient
て接続したら、次のように tail コマンドを実行します (これらの変数は、接続ごとに存在するロガー クラスの一部です)。
command = client.CreateCommand("tail -f /tmp/messages")
result = command.BeginExecute();
stream = command.OutputStream;
次に、ログの読み取り/書き込み機能があります。
public async Task logOutput(IAsyncResult result, Stream stream, TextBox textBox, string logPath)
{
// Clear textbox ( thread-safe :) )
textBox.Invoke((MethodInvoker)(() => textBox.Clear()));
// Create reader for stream and writer for text file
StreamReader reader = new StreamReader(stream, Encoding.UTF8, true, 1024, true);
StreamWriter sw = File.AppendText(logPath);
// Start reading from SSH stream
while (!result.IsCompleted || !reader.EndOfStream)
{
string line = await reader.ReadLineAsync();
if (line != null)
{
// append to textbox
textBox.Invoke((Action)(() => textBox.AppendText(line + Environment.NewLine)));
// append to file
sw.WriteLine(line);
}
}
}
デバイス接続ごとに、次のように呼び出します。
Task.Run(() => logOutput(logger.result, logger.stream, textBox, fileName), logger.token);
問題は CPU 使用率だけです。ロギングプロセスごとに複数のスレッドを作成していると思いますが、それを修正する理由や方法がわかりません。
上記のコードの簡単な修正として、何か目立ったものはありますか? result
またはさらに良い-オブジェクトが新しいテキストを取得したときに新しいデータのみを出力するコールバックを設定する方法はありますか?
すべてのヘルプは大歓迎です!
編集 2021 年 3 月 4 日
CopyToAsync
内部のコードlogOutput()
を次のように変更して、簡単なテストを試みました。
public async Task logOutput(IAsyncResult result, Stream stream, string logPath)
{
using (Stream fileStream = File.Open(logPath, FileMode.OpenOrCreate))
{
// While the result is running, copy everything from the command stream to a file
while (!result.IsCompleted)
{
await stream.CopyToAsync(fileStream);
}
}
}
ただし、これにより、テキスト ファイルにデータが書き込まれなくなり、実際には CPU 使用率がわずかに低下します。
2回目の編集2021年3月4日
さらにデバッグを行うと、新しいデータが入っていない場合にのみ CPU 使用率が高くなるようです。私が知る限り、これはReadLineAsync()
、SSH コマンドから実際に新しいデータがあるかどうかに関係なく、メソッドが常に起動しているためです。可能な限りすべての CPU サイクルを占有して、可能な限り高速に実行されています。それがなぜなのかは完全にはわかりませんが、ここで実際に助けを借りることができます。ReadLineAsync()
SSHコマンドから新しい行が利用可能になるまで待つだけで続行できると思いました。