我有一个程序,它会缓慢生成数据(可以说它是计算密集型的,就像计算pi的数字一样)。它产生很多数据;每个响应可以是1GiB,不会容纳在内存中,并且必须必须按需生成。我正在使用hyper编写Web服务以在请求时生成内容。
我们跳过样板(service_fn
,Server::bind
)。
缓慢生成数据的API可能类似于
use std::io;
impl SlowData {
fn new(initial: &str) -> SlowData {
unimplemented!()
}
fn next_block(&self) -> io::Result<&[u8]> {
unimplemented!()
}
}
type ResponseFuture = Box<Future<Item = Response, Error = GenericError> + Send>;
fn run(req: Request) -> ResponseFuture {
// spawn a thread and:
// initialize the generator
// SlowData::new(&req.uri().path());
// spawn a thread and call slow.next_block() until len()==0
// each byte which comes from next_block should go to the client
// as part of the Body
}
请注意,SlowData::new
的计算量很大。
最理想的是,我们将副本最小化并将&[u8]
直接发送到hyper,而不必将其复制到Vec
或其他东西中。
如何从侧面线程实现超级请求的主体?
答案 0 :(得分:0)
启动线程并通过通道发送块。该通道实现了Stream
,可以使用wrap_stream
从Body
构造超级Stream
:
use futures::{sync::mpsc, Future, Sink, Stream}; // 0.1.27
use hyper::{service::service_fn_ok, Body, Response, Server}; // 0.12.29
use std::{io, thread, time::Duration};
struct SlowData;
impl SlowData {
fn new(_initial: &str) -> SlowData {
thread::sleep(Duration::from_secs(1));
Self
}
fn next_block(&self) -> io::Result<&[u8]> {
thread::sleep(Duration::from_secs(1));
Ok(b"data")
}
}
fn stream() -> impl Stream<Item = Vec<u8>, Error = ()> {
let (tx, rx) = mpsc::channel(10);
thread::spawn(move || {
let sd = SlowData::new("dummy");
let mut tx = tx.wait();
for _ in 0..3 {
tx.send(sd.next_block().unwrap().to_vec()).unwrap();
}
});
rx
}
fn main() {
// Construct our SocketAddr to listen on...
let addr = ([127, 0, 0, 1], 3000).into();
// And a MakeService to handle each connection...
let make_service = || {
service_fn_ok(|_req| {
let data = stream();
Response::new(Body::wrap_stream(data.map_err(|_| "dummy error")))
})
};
// Then bind and serve...
let server = Server::bind(&addr).serve(make_service);
// Finally, spawn `server` onto an Executor...
hyper::rt::run(server.map_err(|e| {
eprintln!("server error: {}", e);
}));
}
目前,无法避免将切片复制到Vec
。编译器的async
/ await
支持应该允许这样做。
另请参阅: