我读了TOKIO的文件 ,我不知道什么是在未来的封装成本同步I / O的最佳途径。
随着反应器框架,我们得到了一个绿色的线程模型的优点是:几个操作系统的线程通过执行处理大量并发任务。
TOKIO的未来模式是需求驱动,这意味着今后本身将查询其内部状态提供有关其完成信息; 允许背压和取消功能。 据我了解,未来的轮询阶段必须是非阻塞运行良好。
在I / O口需要封装可以被看作是一个长期的原子和昂贵的操作。 理想情况下,一个独立的任务将执行I / O和相关的未来将轮询完成状态的I / O线程。
我看到这两个唯一的选项是:
- 包括在阻塞I / O
poll
未来的功能。 - 产卵的OS线程以执行I / O,并使用未来机制轮询其状态下,如示出的文档中
据我所知,没有解决方案是最佳的,并且没有得到充分利用的绿色线程模型(第一次没有在文档劝和第二不通过由电抗器框架提供的执行)。 有另一种解决方案?
理想情况下,一个独立的任务将执行I / O和相关的未来将轮询完成状态的I / O线程。
是的,这就是东京建议和像什么箱子期货cpupool和TOKIO,线程池的创建。 请注意,这并不局限于I / O,而且是有效的任何长期运行的同步任务!
在这种情况下,您计划关闭在池中运行。 池本身进行工作检查,看看是否阻塞闭合尚未完成,并满足Future
特质。
extern crate futures;
extern crate futures_cpupool;
use futures::{future, Future};
use futures_cpupool::CpuPool;
use std::thread;
use std::time::Duration;
fn main() {
let pool = CpuPool::new(8);
let a = pool.spawn_fn(|| {
thread::sleep(Duration::from_secs(3));
future::ok::<_, ()>(3)
});
let b = pool.spawn_fn(|| {
thread::sleep(Duration::from_secs(1));
future::ok::<_, ()>(1)
});
let c = a.join(b).map(|(a, b)| a + b);
let result = c.wait();
println!("{:?}", result);
}
请注意,这是不睡觉的有效方式,它只是对一些阻塞操作的占位符。 如果你确实需要睡觉,使用类似期货定时器或TOKIO定时器 。
你可以看到,总的时间仅为3秒:
$ time ./target/debug/example
Ok(4)
real 0m3.021s
user 0m0.007s
sys 0m0.010s
同样,你可以使用TOKIO,线程池的相同的结果:
extern crate tokio; // 0.1.7
extern crate tokio_threadpool; // 0.1.2
use std::{thread, time::Duration};
use tokio::{prelude::*, runtime::Runtime};
fn delay_for(seconds: u64) -> impl Future<Item = u64, Error = tokio_threadpool::BlockingError> {
future::poll_fn(move || {
tokio_threadpool::blocking(|| {
thread::sleep(Duration::from_secs(seconds));
seconds
})
})
}
fn main() {
let a = delay_for(3);
let b = delay_for(1);
let sum = a.join(b).map(|(a, b)| a + b);
let mut runtime = Runtime::new().expect("Unable to start the runtime");
let result = runtime.block_on(sum);
println!("{:?}", result);
}
无论解决方案是最佳的,并且没有得到充分利用的绿色线程模型
这是正确的 - 因为你没有的东西,是异步的! 您正在尝试两种不同的方法结合起来,必须有一个丑陋的地方一点对他们之间的转换。
第二不穿过由反应器框架提供的执行程序
我不知道你的意思在这里。 这里只有一个在上面的例子中执行; 通过隐含创建的wait
。 线程池有检查,看看如果一个线程是做了一些内部逻辑,但是当用户执行程序,它应该只被触发poll
这样。