如何解决Actix:将共享数据移动到多个线程中的正确方法是什么?
我有一个 config
结构,我在我的 actix 应用程序中共享它,如下所示:
pub fn run(addr: &str,pg_pool: PgPool,config: Settings) -> Result<Server,std::io::Error> {
let pool = web::Data::new(pg_pool);
let arc_config = web::Data::new(Arc::new(config)); // <---
let server = HttpServer::new(move || {
App::new()
.service(exhaust)
.app_data(pool.clone())
.app_data(arc_config.clone()) // <---
})
.bind(addr)?
.run();
然后我有一个处理程序试图生成多个线程并将该 config
结构传递给每个线程:
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>,config: web::Data<Arc<Settings>>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn(move || {
let inner_config = Arc::clone(&config);
get_single_tweet(inner_config.as_ref().deref(),"1401287393228038149");
});
}
HttpResponse::Ok()
}
我的想法是,因为 config
已经包含在 Arc()
中,所以我应该能够在每个线程中Arc::clone()
它,然后将其解引用到基础变量中。
但我收到此错误:
error[E0382]: use of moved value: `config`
--> src/twitter/routes/pull.rs:63:36
|
58 | pub async fn exhaust(pool: web::Data<PgPool>,config: web::Data<Arc<Settings>>) -> impl Responder {
| ------ move occurs because `config` has type `actix_web::web::Data<Arc<Settings>>`,which does not implement the `copy` trait
...
63 | let handle = thread::spawn(move || {
| ^^^^^^^ value moved into closure here,in prevIoUs iteration of loop
64 | let inner_config = Arc::clone(&config);
| ------ use occurs due to use in closure
我正在努力理解为什么这会失败。如果配置在 Arc
内,那么为什么编译器认为我试图移动它而不是增加引用计数?
我还尝试了许多其他方法,但都没有成功:
这样做的正确方法是什么?
解决方法
您需要在移动它之前克隆它。否则,您的第一次迭代必然需要采用它(因为不能保证 config
在任务运行时仍然存在以进行克隆)。然后你会得到你在第二次迭代中看到的错误,因为它也必然需要移动 config
;这就是“在循环的前一次迭代中,这里的值移动到闭包中”的意思。
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>,config: web::Data<Arc<Settings>>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn({
// Clone this here,so the closure gets its very own to move-capture.
let inner_config = config.get_ref().clone();
move || {
get_single_tweet(inner_config.as_ref().deref(),"1401287393228038149");
});
}
}
HttpResponse::Ok()
}
请注意,web::Data
本身已经是 just a wrapper around Arc
,因此您对嵌套的 Arc
有一些冗余。您可能只想:
#[get("/exhaust")]
pub async fn exhaust(pool: web::Data<PgPool>,config: web::Data<Settings>) -> impl Responder {
for _ in 1..16 {
let handle = thread::spawn({
let inner_config = config.clone();
move || {
get_single_tweet(inner_config.as_ref().deref(),"1401287393228038149");
});
}
}
HttpResponse::Ok()
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。