我正在尝试使用tokio::spawn
生成的异步任务中的stdin进行读取。的
执行者被冠以
let mut executor = tokio::runtime::current_thread::Runtime::new().unwrap();
然后使用executor.task(...)
运行主要任务,这会产生其他任务
与tokio::spawn()
。
fn main
然后调用executor.run().unwrap();
以等待所有任务完成。
问题是我什么时候做
let mut stdin = tokio::io::stdin();
let mut read_buf: [u8; 1024] = [0; 1024];
...
stdin.read(&mut read_buf).await
我收到“必须从Tokio运行时的上下文调用阻塞注释的I / O”错误。
依赖项:
futures-preview = { version = "0.3.0-alpha.18", features = ["async-await", "nightly"] }
tokio = "0.2.0-alpha.2"
tokio-net = "0.2.0-alpha.2"
tokio-sync = "0.2.0-alpha.2"
完整代码:
extern crate futures;
extern crate tokio;
extern crate tokio_net;
extern crate tokio_sync;
use std::io::Write;
use std::net::SocketAddr;
use tokio::io::AsyncReadExt;
use tokio::net::tcp::split::{TcpStreamReadHalf, TcpStreamWriteHalf};
use tokio::net::TcpListener;
use tokio_sync::oneshot;
use futures::select;
use futures::future::FutureExt;
#[derive(Debug)]
enum AppErr {
CantBindAddr(std::io::Error),
CantAccept(std::io::Error),
}
fn main() {
let mut executor = tokio::runtime::current_thread::Runtime::new().unwrap();
executor.spawn(async {
match server_task().await {
Ok(()) => {}
Err(err) => {
println!("Error: {:?}", err);
}
}
});
executor.run().unwrap(); // ignores RunError
}
async fn server_task() -> Result<(), AppErr> {
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut listener = TcpListener::bind(&addr).map_err(AppErr::CantBindAddr)?;
loop {
print!("Waiting for incoming connection...");
let _ = std::io::stdout().flush();
let (socket, _) = listener.accept().await.map_err(AppErr::CantAccept)?;
println!("{:?} connected.", socket);
let (read, write) = socket.split();
let (abort_in_task_snd, abort_in_task_rcv) = oneshot::channel();
let (abort_out_task_snd, abort_out_task_rcv) = oneshot::channel();
tokio::spawn(handle_incoming(read, abort_in_task_rcv, abort_out_task_snd));
tokio::spawn(handle_outgoing(
write,
abort_out_task_rcv,
abort_in_task_snd,
));
}
}
async fn handle_incoming(
mut conn: TcpStreamReadHalf,
abort_in: oneshot::Receiver<()>,
abort_out: oneshot::Sender<()>,
) {
println!("handle_incoming");
let mut read_buf: [u8; 1024] = [0; 1024];
let mut abort_in_fused = abort_in.fuse();
loop {
select! {
abort_ret = abort_in_fused => {
// TODO match abort_ret {..}
println!("abort signalled, handle_incoming returning");
return;
},
bytes = conn.read(&mut read_buf).fuse() => {
match bytes {
Err(io_err) => {
println!("io error when reading input stream: {:?}", io_err);
return;
}
Ok(bytes) => {
println!("read {} bytes: {:?}", bytes, &read_buf[0..bytes]);
}
}
}
}
}
}
async fn handle_outgoing(
conn: TcpStreamWriteHalf,
abort_in: oneshot::Receiver<()>,
abort_out: oneshot::Sender<()>,
) {
println!("handle_outgoing");
let mut stdin = tokio::io::stdin();
let mut read_buf: [u8; 1024] = [0; 1024];
let mut abort_in_fused = abort_in.fuse();
loop {
select! {
abort_ret = abort_in_fused => {
println!("abort signalled, handle_outgoing returning");
return;
}
input = stdin.read(&mut read_buf).fuse() => {
match input {
Err(io_err) => {
println!("io error when reading stdin: {:?}", io_err);
return;
}
Ok(bytes) => {
println!("handle_outgoing read {} bytes", bytes);
// TODO
}
}
},
}
}
}
问题:
tokio::spawn
吗?
任务传递给了executor.spawn()
?谢谢
答案 0 :(得分:2)
Tokio stdin
阻止了执行器池中的封闭线程,因为它是用tokio-executor中的blocking
进行注释的。 From the reference:
进入
blocking
函数后,它将移交责任 当前工作队列到另一个线程的处理。
您的代码不起作用,因为您使用的执行程序正在单个线程(tokio::runtime::current_thread::Runtime::new()
)中多路复用任务。因此,将没有其他线程可以为执行程序执行其他任务。
如果您正确配置运行时(具有多个线程的线程池),则代码将正常工作:
fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut executor = rt.executor();
executor.spawn(async {
match server_task().await {
Ok(()) => {}
Err(err) => {
println!("Error: {:?}", err);
}
}
});
rt.shutdown_on_idle();
}
另请参见: How can I stop reading from a tokio::io::lines stream?