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

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

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

问题

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

以下是我的代码:

use trust_dns_resolver::{
    config::{ResolverConfig, ResolverOpts},
    TokioAsyncResolver,
};

fn main() {
    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

    rt.block_on(async {
        let cb_domain_iter = vec!["example.com.", "google.com.", "facebook.com."];

        let resolver = Arc::new(
            TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
                .expect("Could not create resolver"),
        );

        let tasks = cb_domain_iter.iter().map(move |domain| {
            let resolver_ref = resolver.clone();
            let domain_ref = domain.to_string(); // 如果必须的话,我们可以通过将cb_domain_iter放在Arc<>后面来消除这个.clone()
            tokio::spawn(resolver_ref.lookup_ip(domain_ref))
        });

        for join in tasks {
            join.await;
        }
    })
}

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

error[E0597]: `resolver_ref` does not live long enough
  --> src/bin/test.rs:26:26
   |
26 |             tokio::spawn(resolver_ref.lookup_ip(domain_ref))
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                          |
   |                          borrowed value does not live long enough
   |                          argument requires that `resolver_ref` is borrowed for `'static`
27 |         });
   |         - `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:

use trust_dns_resolver::{
    config::{ResolverConfig, ResolverOpts},
    TokioAsyncResolver,
};

fn main() {
    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

    rt.block_on(async {
        let cb_domain_iter = vec![&quot;example.com.&quot;, &quot;google.com.&quot;, &quot;facebook.com.&quot;];

        let resolver = Arc::new(
            TokioAsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
                .expect(&quot;Could not create resolver&quot;),
        );

        let tasks = cb_domain_iter.iter().map(move |domain| {
            let resolver_ref = resolver.clone();
            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;
            tokio::spawn(resolver_ref.lookup_ip(domain_ref))
        });

        for join in tasks {
            join.await;
        }
    })
}

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:

error[E0597]: `resolver_ref` does not live long enough
  --&gt; src/bin/test.rs:26:26
   |
26 |             tokio::spawn(resolver_ref.lookup_ip(domain_ref))
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                          |
   |                          borrowed value does not live long enough
   |                          argument requires that `resolver_ref` is borrowed for `&#39;static`
27 |         });
   |         - `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的未来中,而不是传递给它一些临时值:

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:

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:

确定