使用hyper
,我需要建立HTTP连接并读取结果。
我想把整个事情包裹起来,
所以我开始一个线程
并使用recv_timeout
等待它。
仅包装send
作品,
但我也要包裹read_to_string
。
这是代码:
fn send_request(url: &str) -> Result<Response, MyAppError> {
let mut c = Client::new();
let mut req = c.get(url);
req.send().map_err(|e| MyAppError::TcpError(e))
}
fn get_url(url: &str, mut buf: &mut String) -> Result<u16, MyAppError> {
let mut resp = send_request(url)?;
resp.read_to_string(&mut buf).map_err(|e| MyAppError::ReadError(e))?;
Ok(resp.status.to_u16())
}
fn get_url_with_timeout_2(url: &str, mut buf: &mut String) -> Result<u16, MyAppError> {
let (tx, rx) = mpsc::channel();
let url = url.to_owned();
let t = thread::spawn(move || {
match tx.send(get_url(&url, &mut buf)) {
Ok(()) => {} // everything good
Err(_) => {} // we have been released, no biggie
}
});
match rx.recv_timeout(Duration::from_millis(5000)) {
Ok(resp) => resp,
Err(_) => Err(MyAppError::Timeout),
}
}
不幸的是我遇到了编译错误:
error[E0477]: the type `[closure@src/main.rs:53:25: 58:4 tx:std::sync::mpsc::Sender<std::result::Result<u16, MyAppError>>, url:std::string::String, buf:&mut std::string::String]` does not fulfill the required lifetime
--> src/main.rs:53:11
|
53 | let t = thread::spawn(move || {
| ^^^^^^^^^^^^^
|
= note: type must outlive the static lifetime
如何将缓冲区传递给线程, 让它填补它, 然后在主线程上打印出缓冲区?
(这是Rust 1.15.1。)
This repository提供了完整的main.rs
,并显示了获取网页的三个示例:
没有超时。
仅在send
上暂停。
整个事情都超时。
如果你拿出3,它就会编译并运行。 我可以改变3来做这项工作吗?
顺便说一句,提出网络请求实际上只是&#34;场合&#34;对于这个问题。我已经看过this question about doing a timeout了。我自己感兴趣的不是超时本身,而是关于如何在一个线程上填充缓冲区并在另一个线程上读取它。
Share mutable object between threads建议使用Arc
和Mutex
在线程之间安全地共享数据。以下是对此的尝试:
fn get_url_with_timeout_3(url: &str) -> Result<(u16, String), MyAppError> {
let (tx, rx) = mpsc::channel();
let url = url.to_owned();
let shbuf = Arc::new(Mutex::new(String::new()));
let shbuf2 = shbuf.clone();
let t = thread::spawn(move || {
let mut c = Client::new();
let mut req = c.get(&url);
let mut ret = match req.send() {
Ok(mut resp) => {
let mut buf2 = shbuf2.lock().unwrap();
match resp.read_to_string(&mut buf2) {
Ok(_) => Ok(resp.status.to_u16()),
Err(e) => Err(MyAppError::ReadError(e)),
}
}
Err(e) => Err(MyAppError::TcpError(e)),
};
match tx.send(ret) {
Ok(()) => {} // everything good
Err(_) => {} // we have been released, no biggie
}
});
match rx.recv_timeout(Duration::from_millis(5000)) {
Ok(maybe_status_code) => {
let buf2 = shbuf.lock().unwrap();
Ok((maybe_status_code?, *buf2))
}
Err(_) => Err(MyAppError::Timeout),
}
}
这为我提供了错误cannot move out of borrowed content
,因为它试图返回*buf2
(这是有道理的,因为它会从Mutex
泄漏数据),但我不是确定如何在Rust可以看到模式的结构中表达这一点。
如果请求线程超时,它会永久保持锁定 - 但我从不尝试读取缓冲区,所以谁在乎。如果请求线程完成,它将释放锁并消失,主线程将保留唯一的引用。我可以说它是安全的,但我不确定如何说服编译器。
我不允许回答这个问题,因为它应该是重复的,但我已经使用评论中的想法为my GitHub repository添加了3个有效的实现。