首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SSH.NET实时测井高CPU

SSH.NET实时测井高CPU
EN

Stack Overflow用户
提问于 2021-03-04 21:38:57
回答 1查看 341关注 0票数 0

让我在这个问题的序言中说,我绝对不是一个专业的C#程序员,而且到目前为止,我的大多数小程序几乎都是蛮横的。

我正在开发一个小型WinForms应用程序,将SSH放入几个设备中,在每个设备上tail -f一个日志文件,并在TextBoxes中显示实时输出,同时保存到日志文件中。现在,它可以工作,但是在日志记录过程中占用了我将近30%的CPU,而且我肯定我做错了什么。

在创建了SshClient和connection之后,我运行了如下的尾命令(这些变量是每个连接都存在的记录器类的一部分):

代码语言:javascript
复制
command = client.CreateCommand("tail -f /tmp/messages")
result = command.BeginExecute();
stream = command.OutputStream;

然后,我有一个日志读取/写入功能:

代码语言:javascript
复制
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);
        }
    }
}

我将其称为以下方式,每个设备连接:

代码语言:javascript
复制
Task.Run(() => logOutput(logger.result, logger.stream, textBox, fileName), logger.token);

一切正常工作,只是CPU的使用才是问题所在。我猜我每个日志记录进程创建的线程不止一个,但我不知道为什么或者如何解决这个问题。

对于上面的代码,有什么东西是简单的修复吗?或者更好的是--是否有一种方法可以设置一个回调,该回调只在result对象获得新文本时打印新数据?

所有的帮助都非常感谢!

编辑3/4/2021

我尝试使用CopyToAsync进行一个简单的测试,方法是将logOutput()中的代码更改为:

代码语言:javascript
复制
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编辑3/4/2021

如果进行更多的调试,那么只有当没有新的数据进入时,CPU的高使用率才会出现。据我所知,这是因为ReadLineAsync()方法一直在触发,而不管是否有来自运行中的SSH命令的新数据,而且它正在尽可能快地运行,占用了所有的CPU周期。我不太清楚这是为什么,我真的需要一些帮助。我原以为ReadLineAsync()只需等待从SSH命令获得的新行才能继续。

EN

回答 1

Stack Overflow用户

发布于 2021-03-05 01:39:41

最终解决方案比我想象的要简单得多。

在SSH.NET中有一个已知的bug中,当没有实际的新数据接收时,命令的OutputStream将不断地输出空数据。这使得我的代码中的while循环尽可能快地运行,消耗了进程中的一堆CPU。

解决方案只是在循环中添加一个短的异步延迟。我只在接收到的数据是null时才包含延迟,这样当有实际的有效数据通过时,读取就不会中断。

代码语言:javascript
复制
while (!result.IsCompleted && !token.IsCancellationRequested)
{
    string line = await reader.ReadLineAsync();
    // Append line if it's valid
    if (string.IsNullOrEmpty(line))
    {
        await Task.Delay(10);  // prevents high CPU usage
        continue;
    } 
    // Append line to textbox
    textBox.Invoke((Action)(() => textBox.AppendText(line + Environment.NewLine)));
    // Append line to file
    writer.WriteLine(line);
}

在Ryzen 5 3600上,这使我的CPU使用率从30%到40%,而当程序运行时,即使是在数据流动的情况下,也不到1%。好多了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66483431

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档