【发布时间】: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(&hostname).map_err(|e| format!("{}:{}", hostname, e))?;另外,format!的结果不需要.to_string(),它已经是String了。 -
@Shepmaster 重写以简化代码
-
@Shepmaster 我只是不知道,如何为 io 特定代码制作 mre,因为线程等待的执行方式与我预期的不同
-
您说但是如果使用 TCP,它开始表现很差,您能更明确地说明您的意思吗?它的表现如何?为什么你认为它应该更好?您是否在发布模式下运行代码?
标签: multithreading rust rayon