我有一些目前看起来像这样的Rust代码
fn read_stdin(mut tx: mpsc::Sender<String>) {
loop {
// read from stdin and send value over tx.
}
}
fn sleep_for(n: u64) -> impl Future<Item = (), Error = ()> {
thread::sleep(time::Duration::from_millis(n));
println!("[{}] slept for {} ms", Local::now().format("%T%.3f"), n);
future::ok(())
}
fn main() {
let (stdin_tx, stdin_rx) = mpsc::channel(0);
thread::spawn(move || read_stdin(stdin_tx));
let server = stdin_rx
.map(|data| data.trim().parse::<u64>().unwrap_or(0))
.for_each(|n| tokio::spawn(sleep_for(n * 100)));
tokio::run(server);
}
它使用tokio和Futures,目的是运行一些“ cpu繁重”的工作(由sleep_for
函数模拟),然后将一些东西输出到stdout
。
当我运行它时,看起来一切正常,我得到了这个输出
2
[00:00:00.800] slept for 200 ms
10
1
[00:00:01.800] slept for 1000 ms
[00:00:01.900] slept for 100 ms
第一个值为2
的输出与预期完全一样,我看到200毫秒后打印的时间戳。但是对于接下来的输入,很明显sleep_for
函数是顺序执行的,而不是并发执行的。
我想看的输出是
2
[00:00:00.800] slept for 200 ms
10
1
[00:00:00.900] slept for 100 ms
[00:00:01.900] slept for 1000 ms
似乎要获得我想要的输出,我想同时执行sleep_for(10)
和sleep_for(1)
。我将如何使用Rust和Tokio在Rust中进行此操作?
(注意:时间戳的实际值并不重要,我会更多地使用它们来显示程序中执行的顺序)
答案 0 :(得分:0)
找到了使用futures-timer
条板箱的解决方案。
use chrono::Local;
use futures::{future, sync::mpsc, Future, Sink, Stream};
use futures_timer::Delay;
use std::{io::stdin, thread, time::Duration};
fn read_stdin(mut tx: mpsc::Sender<String>) {
let stdin = stdin();
loop {
let mut buf = String::new();
stdin.read_line(&mut buf).unwrap();
tx = tx.send(buf).wait().unwrap()
}
}
fn main() {
let (stdin_tx, stdin_rx) = mpsc::channel(0);
thread::spawn(move || read_stdin(stdin_tx));
let server = stdin_rx
.map(|data| data.trim().parse::<u64>().unwrap_or(0) * 100)
.for_each(|delay| {
println!("[{}] {} ms -> start", Local::now().format("%T%.3f"), delay);
tokio::spawn({
Delay::new(Duration::from_millis(delay))
.and_then(move |_| {
println!("[{}] {} ms -> done", Local::now().format("%T%.3f"), delay);
future::ok(())
})
.map_err(|e| panic!(e))
})
});
tokio::run(server);
}
问题在于,宁可让未来停滞不前然后通知当前任务,问题中显示的代码只是使线程处于休眠状态,因此无法取得任何进展。
更新:现在我遇到了tokio-timer
,这似乎是实现此目的的标准方法。