如何处理 tokio::spawn 闭包需要“static”和“&self”?

2023-12-03

我无法理解如何编写封装在一个结构中的并发异步代码。

我不确定如何准确解释这个问题,所以我会尝试用一个例子来解释。

假设我有一个UdpServer结构。该结构有多个与其行为相关的方法(例如,handle_datagram, deserialize_datagram, etc)
如果我想让代码并发,我将生成 tokio 任务,这需要提供给它的闭包是静态的,这意味着我无法调用&self从这个任务中只要&self不是静态的,这意味着我无法调用self.serialize_datagram().

我理解这个问题(不能保证结构会比线程寿命更长),但看不到解决它的正确方法。我知道可以将函数移出 impl,但这对我来说看起来不是一个好的解决方案。
另外,即使我们暂时假设我could take &self作为静态的,由于某种原因,这段代码在我看来仍然不正确(我猜还不够生锈)。
另一个“解决方案”是采取self: Arc<Self>代替&self,但这感觉更糟。

所以我假设有一些我不知道的模式。 有人可以向我解释一下我应该如何重构整个事情吗?

示例代码:

struct UdpServer {}
impl UdpServer {
    pub async fn run(&self) {
        let socket = UdpSocket::bind(self.addr).await.unwrap();
        loop {
            let mut buf: &mut [u8] = &mut [];
            let (_, _) = socket.recv_from(&mut buf).await.unwrap();

            // I spawn tokio task to enable concurrency
            tokio::spawn(async move {
                // But i can't use &self in here because it's not static.
                let datagram = self.deserialize_datagram(buf).await;
                self.handle_datagram(()).await;
            });
        }
    }

    pub async fn deserialize_datagram(&self, buf: &mut [u8]) -> Datagram {
        unimplemented!()
    }

    pub async fn handle_datagram(&self, datagram: Datagram) {
        unimplemented!()
    }
}

目前唯一的方法是使self通过使用持续任意长的时间Arc. Since run()是一个方法UdpServer,它需要更改为Arc<Self>,你考虑过但拒绝了,因为感觉更糟。尽管如此,这就是做到这一点的方法:

pub async fn run(self: Arc<Self>) {
    let socket = UdpSocket::bind(&self.addr).await.unwrap();
    loop {
        let mut buf: &mut [u8] = &mut [];
        let (_, _) = socket.recv_from(&mut buf).await.unwrap();

        tokio::spawn({
            let me = Arc::clone(&self);
            async move {
                let datagram = me.deserialize_datagram(buf).await;
                me.handle_datagram(datagram).await;
            }
        });
    }
}

操场

有趣的是,smol 异步运行时实际上可能会提供您正在寻找的东西,因为它的执行者具有一生。该生命周期与调用者环境中的值相关联,并且执行器上生成的 future 可能会引用它。例如,这样编译:

use futures_lite::future;
use smol::{Executor, net::UdpSocket};

struct Datagram;

struct UdpServer {
    addr: String,
}

impl UdpServer {
    pub async fn run<'a>(&'a self, ex: &Executor<'a>) {
        let socket = UdpSocket::bind(&self.addr).await.unwrap();
        loop {
            let mut buf: &mut [u8] = &mut [];
            let (_, _) = socket.recv_from(&mut buf).await.unwrap();

            ex.spawn({
                async move {
                    let datagram = self.deserialize_datagram(buf).await;
                    self.handle_datagram(datagram).await;
                }
            }).detach();
        }
    }

    pub async fn deserialize_datagram(&self, _buf: &mut [u8]) -> Datagram {
        unimplemented!()
    }

    pub async fn handle_datagram(&self, _datagram: Datagram) {
        unimplemented!()
    }
}

fn main() {
    let server = UdpServer { addr: "127.0.0.1:8080".to_string() };
    let ex = Executor::new();
    future::block_on(server.run(&ex));
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何处理 tokio::spawn 闭包需要“static”和“&self”? 的相关文章

随机推荐

  • 仅在 apex 报告的某些行上显示“编辑”链接

    我有以下报告结构 显示全年产品的销售目标和销售额 每个产品都有两行 一行显示销售额 一行显示 sales target 目前 我的报告在报告的每一行旁边都有一个编辑链接 有没有办法从 sales target 行中删除编辑链接 select
  • 无法使用 PRAW 从某些 Reddit 子版块中获取随机帖子

    我正在尝试使用此代码让一个不和谐的机器人从reddit发送图像 只是为了抓取而不是发送 def random post subreddit while True post reddit subreddit subreddit random
  • Android:如何获取自定义View的高度和宽度? [复制]

    这个问题在这里已经有答案了 我该如何使用getMeasuredWidth and getMeasuredHeight 它总是返回 0 这和有什么区别getHeight and getWidth 刚刚找到了获取自定义视图的高度和宽度的解决方案
  • SQLite中保存资源路径

    我需要将图像保存在 SQLite 数据库的资源文件夹中 该数据库是预加载的 复制到数据 路径 因此在运行时不会填充 我尝试将其保存在 SQLite 的文本字段中 R drawable picture1 我的drawable文件夹中有大约30
  • MySQL FULLTEXT 不适用于多个字段

    我有一个标准的 MySQL 全文查询 如下所示 SELECT FROM accounts WHERE MATCH first name username AGAINST stringhere 问题是 它找不到该字段的全文索引first na
  • 通过 jQuery 添加 JSF 标签/组件

    这是我所做的 var a document getElementById panelForm tableId01
  • NSIS 系统 kernel32::LoadLibrary 不搜索 Outdir 或 Path

    我正在尝试在 NSIS 安装程序中加载并调用 C 库 DLL 的函数 当我尝试加载 DLL 时 发出错误 126 ERROR MOD NOT FOUND 这是我用来测试的最小安装程序脚本 OutFile Main exe ShowInstD
  • 如何配置Json.NET自定义序列化?

    由于我无法控制的原因 我从外部服务返回的数据被格式化为字符串数组的数组 string one string two 我试图将其反序列化为具有两个属性的对象 public class MyObject public string Proper
  • ajax 调用导致错误而不是成功

    在我的 ASP net mvc3 项目中 我使用 ajax 调用将 json 数据发送到控制器公司中的创建操作方法 但是当我调试ajax调用时 它总是以错误结果而不是成功结果结束 阿贾克斯调用 ajax url Company Create
  • 在javascript中移动对象元素位置

    我正在尝试找到一种将对象元素移动到特定位置的方法 例如 我有这个对象 element1 object element2 element3 我搜索将 element3 移动到第一个位置 element3 element1 element2 感
  • 从 PDO 准备好的语句中获取原始 SQL 查询字符串

    在准备好的语句上调用 PDOStatement execute 时 有没有办法让原始 SQL 字符串执行 出于调试目的 这将非常有用 我假设您的意思是您想要最终的 SQL 查询 并将参数值插入其中 我知道这对于调试很有用 但这不是准备好的语
  • 如何为等待函数调用添加超时

    向等待函数添加超时的最佳方法是什么 Example lets pretend this is in a library that I m using and I can t mess with the guts of this thing
  • 按平均值排名的箱线图

    我想显示多个变量的箱线图 并按列均值降序排列它们 就像在绩效分析包裹 我使用以下代码生成箱线图 zx lt replicate 5 rnorm 50 zx means lt colMeans zx na rm TRUE boxplot zx
  • django 和 facebook:代表用户执行第三方登录的 facebook web 应用程序的安全性和设计

    我正在编写一个 Facebook 画布 Web 应用程序 它执行对第三方网站的登录 使用 urllib 并代表用户执行操作 这意味着我有2个账户 用户在我的网络应用程序中拥有的帐户 通过 facebook 以及应用程序用来代表他们执行登录的
  • Android Parcelable 对象返回 Null

    我有产品类 我想将产品对象从一项活动传递到另一项活动 我已经这样实现了 public class Product implements Parcelable private double availableQuantity private
  • 函数修改列表

    def make Ab A b n len A Ab list A for index in range 0 n Ab index append b index 0 print A return Ab copy A 0 0 1 0 1 0
  • VSCode 片段触发器之前有文本吗?

    我想在 VSCode 中创建一个显示 PHP 箭头的代码片段 当我按 键然后按 TAB 键时 我想要 PHP 箭头 gt 这是我的代码片段 PHP arrow prefix body gt 0 description PHP Arrow g
  • R - 将数据帧转换为格式为 featureName:featureValue [重复] 的数据集

    这个问题在这里已经有答案了 原来我想要的格式叫 SVM 轻 并在这里描述http svmlight joachims org 我有一个数据框 我想将其转换为格式如下的文本文件 output featureIndex featureValue
  • 无法在子进程命令中使用 grep

    我的子进程命令有问题 我喜欢 grep 出与 Online 行匹配的行 def run command command p subprocess Popen command shell False stdout subprocess PIP
  • 如何处理 tokio::spawn 闭包需要“static”和“&self”?

    我无法理解如何编写封装在一个结构中的并发异步代码 我不确定如何准确解释这个问题 所以我会尝试用一个例子来解释 假设我有一个UdpServer结构 该结构有多个与其行为相关的方法 例如 handle datagram deserialize