【问题标题】:Rust rayon tcp blockingRust 人造丝 tcp 阻塞
【发布时间】:2020-05-02 14:18:42
【问题描述】:

我正在编写一个程序,它使用 ssh 在服务器上执行命令并获取输出。

没看懂的部分在代码下面。

如果函数等待然后返回一个字符串,它会按预期工作,但如果与 TCP 一起工作,它会开始表现得很糟糕。我希望在 100 台主机上使用 100 个线程会快 100 倍, 因为会同时打开 100 个套接字。

在睡眠版本中,更改poolThreads直接影响执行时间。在带有 TCP 流的版本中,将 pool 从 1 更改为 100 并使用 100 个主机只会将其从 90 加速到 67,因为某些主机处于脱机状态。

我阅读了文档,但找不到任何可以帮助我的东西。

use clap::{App, Arg};
use rayon::prelude::*;
use rayon::ThreadPoolBuilder;
use ssh2::Session;
use std::fmt::Display;
use std::io::prelude::*;
use std::io::{BufReader, Read};
use std::net::{TcpStream, ToSocketAddrs};
use std::thread::sleep;
use std::time::Duration;

fn process_host<A>(hostname: A) -> Result<String, String>
where
    A: ToSocketAddrs + Display,
{
    sleep(Duration::from_secs(1));
    return Ok(hostname.to_string());
    // here is the problem
    // -----------------------------------------------------------
    let tcp = match TcpStream::connect(&hostname) {
        Ok(a) => a,
        Err(e) => {
            return Err(format!("{}:{}", hostname, e).to_string());
        }
    };
    let mut sess = match Session::new() {
        Ok(a) => a,
        Err(e) => {
            // todo logging
            return Err(format!("{}:{}", hostname, e).to_string());
        }
    };
    sess.set_tcp_stream(tcp);
    match sess.handshake() {
        Ok(a) => a,
        Err(e) => {
            return Err(format!("{}:{}", hostname, e).to_string());
        }
    };
    Ok(format!("{}", hostname))
}


fn main() {

    let hosts = vec!["aaaaa:22", "bbbbbbb:22"];
    let pool = ThreadPoolBuilder::new()
        .num_threads(10)
        .build()
        .expect("failed creating pool");
    pool.install(|| {
        hosts
            .par_iter()
            .map(|x| process_host(x))
            .for_each(|x| println!("{:?}", x))
    });
}

【问题讨论】:

  • 很难回答您的问题,因为它不包含minimal reproducible example。代码中存在许多似乎不需要重现问题的部分。如果您尝试尽可能地Rust Playground 上重现您的错误,这将使我们更容易为您提供帮助,否则在全新的 Cargo 项目中,然后edit 您的问题包括附加信息。您可以使用Rust-specific MRE tips 来减少您在此处发布的原始代码。谢谢!
  • FWIW,你的错误处理代码可以大大简化:let tcp = TcpStream::connect(&amp;hostname).map_err(|e| format!("{}:{}", hostname, e))?; 另外,format! 的结果不需要.to_string(),它已经是String了。
  • @Shepmaster 重写以简化代码
  • @Shepmaster 我只是不知道,如何为 io 特定代码制作 mre,因为线程等待的执行方式与我预期的不同
  • 您说但是如果使用 TCP,它开始表现很差,您能更明确地说明您的意思吗?它的表现如何?为什么你认为它应该更好?您是否在发布模式下运行代码?

标签: multithreading rust rayon


【解决方案1】:

要调试这样的问题,您需要分析程序浪费时间的地方。 有办法: 剖析和分析 TCP 连接。
我建议你 2 方式,因为它更容易。 使用wireshark转储流量,通过端口22过滤。 在此之后,使用conversations 标签。在这里您可以按时间对连接进行排序,并且可以看到,由于 ssh 连接没有时间限制,该程序不会加速。

【讨论】:

    猜你喜欢
    • 2020-02-16
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 2016-08-16
    • 2015-01-15
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多