Rust 为什么即使在未来解决后,在循环中使用带有东京期货的克隆超级客户端仍会阻塞?

Rust 为什么即使在未来解决后,在循环中使用带有东京期货的克隆超级客户端仍会阻塞?,rust,rust-tokio,hyper,Rust,Rust Tokio,Hyper,我有一个以固定间隔更新缓存数据的服务。每隔N秒,它将使用循环(tokio::run(future\u update(http\u client.clone()))触发future,但它不会返回到解析future的父函数。循环阻塞,我只得到一次迭代 当我创建一个新的超HTTP客户端而不是传递一个克隆的客户端时,一切都正常工作。它也不起作用 pub fn触发器缓存重新加载(http\u客户端:Arc){ 让load_interval_sec=get_load_interval_sec(conf.lo

我有一个以固定间隔更新缓存数据的服务。每隔N秒,它将使用循环(
tokio::run(future\u update(http\u client.clone())
)触发future,但它不会返回到解析future的父函数。循环阻塞,我只得到一次迭代

当我创建一个新的超HTTP客户端而不是传递一个克隆的客户端时,一切都正常工作。它也不起作用

pub fn触发器缓存重新加载(http\u客户端:Arc){
让load_interval_sec=get_load_interval_sec(conf.load_interval_seconds.clone());
std::thread::spawn(移动| |循环{
让http_client=http_client.clone();
信息!(“醒来”);
东京:运行(管道(http_客户端));
信息(
“管道运行完成。呼,现在我需要睡眠{}秒。睡眠”,
加载间隔秒
);
std::thread::sleep(std::time::Duration::from_secs(load_interval_secs));
});
}
fn管道(
客户:Arc,
)->盒子{
let res=fetch\u message\u payload()//此调用的返回类型为Box
.map_err(错误::from)
.然后| | |{
//让client=hyper::client::builder().max_idle_per_host(1)。build_http();
//如果我每次都在这里创建新的客户端并使用它,那么所有的工作都很好。
刷新缓存(客户端)//此调用的返回类型为Box
.map_err(错误::from)
.然后| arg |{
调试!(“刷新缓存已完成”);
Ok(arg)
})
});
设res=res.or|else(| e |{
错误!(“错误{:?}”,e);
好(())
});
框::新(res)
}
调用一次
触发器\u缓存\u重新加载
后,我得到
的“唤醒”
日志消息。在成功完成future一段时间后,我还会收到
“刷新\u缓存完成”
日志消息。无论是否带有
Arc
,我都不会收到
“睡眠”日志消息


如果我每次在将来创建一个新的客户端,我就能够获得
“休眠”
日志消息。

tokio::run
每次调用它时都会创建一个全新的事件循环和线程池(reactor+executor)。这真的不是你想做的

超级客户端将其状态绑定到上一个事件循环,如果在新的事件循环上进行轮询,则无法取得进展,因为旧的事件循环将在
run
完成后被销毁。这就是为什么新客户机可以工作,但不能重用旧客户机

这里有两种解决方案:

  • 如果您的应用程序的其余部分没有使用tokio,我将只使用同步。如果您不需要太多的并发性,那么这里的同步解决方案要容易得多

  • 如果您使用的是tokio,请在另一个Future内与一起运行检查,然后在事件循环上等待指定的时间量

异步/等待示例 新的async/await支持使这样的代码更容易编写

此示例目前仅适用于
夜间
编译器和
tokio-0.3.0-alpha.2
以及当前
hyper
主分支:

[dependencies]
tokio = "0.3.0-alpha.2"
tokio-timer = "0.3.0-alpha.2"
hyper = { git = "https://github.com/hyperium/hyper.git" }
使用tokio::timer::Interval;
使用hyper::{Client,Uri};
使用std::time::Duration;
#[tokio::main]
异步fn main(){
让client=client::new();
设第二个_间隔=120;
让mut interval=interval::new_interval(持续时间::from_secs(second_interval));
让uri=uri::from_static(“http://httpbin.org/ip");
环路{
让res=Client.get(uri.clone()).wait.unwrap();
//做你需要做的事来回应。。。
interval.next()等待;
}
}