如何使克隆的 Arc 在 Rust 的 tokio 任务中存活足够长的时间?

huangapple go评论92阅读模式
英文:

How can I make a cloned Arc live long enough for a tokio task in Rust?

问题

我在说服编译器确保某些变量的生命周期足够长。

以下是我的代码:

  1. use trust_dns_resolver::{
  2. config::{ResolverConfig, ResolverOpts},
  3. TokioAsyncResolver,
  4. };
  5. fn main() {
  6. let rt = tokio::runtime::Builder::new_current_thread()
  7. .enable_all()
  8. .build()
  9. .unwrap();
  10. rt.block_on(async {
  11. let cb_domain_iter = vec!["example.com.", "google.com.", "facebook.com."];
  12. let resolver = Arc::new(
  13. TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
  14. .expect("Could not create resolver"),
  15. );
  16. let tasks = cb_domain_iter.iter().map(move |domain| {
  17. let resolver_ref = resolver.clone();
  18. let domain_ref = domain.to_string(); // 如果必须的话,我们可以通过将cb_domain_iter放在Arc<>后面来消除这个.clone()
  19. tokio::spawn(resolver_ref.lookup_ip(domain_ref))
  20. });
  21. for join in tasks {
  22. join.await;
  23. }
  24. })
  25. }

由于我.await每个JoinHandleresolvercb_domain_iter应该足够长以供tokio任务使用。然而,编译器并不知道这一点,如错误消息所示:

  1. error[E0597]: `resolver_ref` does not live long enough
  2. --> src/bin/test.rs:26:26
  3. |
  4. 26 | tokio::spawn(resolver_ref.lookup_ip(domain_ref))
  5. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  6. | |
  7. | borrowed value does not live long enough
  8. | argument requires that `resolver_ref` is borrowed for `'static`
  9. 27 | });
  10. | - `resolver_ref` dropped here while still borrowed

这使我陷入了一些困境。从错误消息告诉我的来看,我理解创建的引用克隆在tokio spawn开始之前就被丢弃了,但是我很难使tokio任务同步地拥有引用。

也许有一些通过改变代码结构来强制其工作的方法,但我真的希望有一些像这里的.map(...)提供的简单而功能性的东西。因此,理想情况下,解决方案将继续使用rust的函数式特性。

英文:

I am having convincing the compiler that certain variables live long enough.

Here is my code:

  1. use trust_dns_resolver::{
  2. config::{ResolverConfig, ResolverOpts},
  3. TokioAsyncResolver,
  4. };
  5. fn main() {
  6. let rt = tokio::runtime::Builder::new_current_thread()
  7. .enable_all()
  8. .build()
  9. .unwrap();
  10. rt.block_on(async {
  11. let cb_domain_iter = vec![&quot;example.com.&quot;, &quot;google.com.&quot;, &quot;facebook.com.&quot;];
  12. let resolver = Arc::new(
  13. TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
  14. .expect(&quot;Could not create resolver&quot;),
  15. );
  16. let tasks = cb_domain_iter.iter().map(move |domain| {
  17. let resolver_ref = resolver.clone();
  18. let domain_ref = domain.clone(); // we can get rid of this .clone() if we really have to by putting cb_domain_iter behind an Arc&lt;&gt;
  19. tokio::spawn(resolver_ref.lookup_ip(domain_ref))
  20. });
  21. for join in tasks {
  22. join.await;
  23. }
  24. })
  25. }

Since I .await each of the JoinHandles, the resolver and cb_domain_iter should live long enough for the tokio tasks. However, the compiler is unaware of this as seen in the error message:

  1. error[E0597]: `resolver_ref` does not live long enough
  2. --&gt; src/bin/test.rs:26:26
  3. |
  4. 26 | tokio::spawn(resolver_ref.lookup_ip(domain_ref))
  5. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  6. | |
  7. | borrowed value does not live long enough
  8. | argument requires that `resolver_ref` is borrowed for `&#39;static`
  9. 27 | });
  10. | - `resolver_ref` dropped here while still borrowed

This brings me to a bit of a dillema. From what it tells me, I understand that the reference clone I create is dropped before the tokio spawn starts, but I am having trouble making the tokio task own the reference synchronously.

There may be ways to coerce this to work by changing the structure of the code, but I was really hoping for something simple & functional like what the .map(...) is providing here. So ideally the solution continues to use the functional features of rust.

答案1

得分: 1

我认为解决方案是将resolver_refdomain_ref简单地移到您传递给spawn的未来中,而不是传递给它一些临时值:

  1. tokio::spawn(async move { resolver_ref.lookup_ip(domain_ref).await })
英文:

I think the solution is to simply move resolver_ref and domain_ref into the future you give to spawn instead of giving it some temporary:

  1. tokio::spawn(async move {resolver_ref.lookup_ip(domain_ref).await })

huangapple
  • 本文由 发表于 2023年5月25日 03:30:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76326844.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定