trait MethodTrait {
async fn async_method(&self);
}
#[derive(Clone)]
struct MyStruct {}
impl MethodTrait for MyStruct {
async fn async_method(&self) {
todo!() // 占位
}
}
struct Demo<T>
where
T: MethodTrait + Clone + Sync + Send + 'static,
{
parser: T,
}
impl<T> Demo<T>
where
T: MethodTrait + Clone + Sync + Send + 'static,
{
fn new(parser: T) -> Self {
Demo { parser }
}
async fn execute(&self) {
let parser = self.parser.clone();
tokio::spawn(async move {
// parser.async_method().await; // 这里会报错
test_fn().await; // 这里正常执行
});
}
}
#[tokio::main]
async fn main() {
let my_struct = MyStruct {};
let demo = Demo::new(my_struct);
demo.execute().await;
}
async fn test_fn() {
println!("hello world")
}
错误信息: the trait Send
is not implemented for impl Future<Output = ()>
, which is required by : Send
这里没搞懂为什么不能直接写async方法,要写同步方法然后自己手动约束返回值的send。
1
共 9 条评论, 1 页
评论区
写评论--
👇
LazyBoy: tokio默认是启用多线程调度的,所以需要任务满足Send;如果想要单线程的话,需要自己手动指定一个单线程的调度策略
--
👇
缘罪: 我没搞懂这块为啥需要约束Send
在 Rust 中,Send 和 Sync 是兩個重要的標記 trait,它們決定了類型是否可以在多線程之間安全地發送(Send)或者類型本身是否可以安全地在多個線程中共享(Sync)。
當你在 Demo 結構體的方法中調用 tokio::spawn 時,你實際上是在創建一個新的異步任務,並且這個任務需要能夠在任何線程中運行,因此這個任務必須實現 Send。而在你的代碼中,parser.async_method().await; 這一行會觸發一個錯誤,因為 async_method 的返回類型是一個 Future,而默認情況下,閉包和其捕獲的環境(在這個例子中是 parser 的克隆)可能不會自動實現 Send。
為了解決這個問題,你需要確保所有閉包捕獲的數據以及閉包本身都是可發送的(即實現了 Send)。此外,如果你的異步方法 async_method 返回的 Future 也必須是 Send 的。
為了修正這段代碼,你可以確保 parser 實現了 Send 和 Sync,並且在閉包中使用的任何其他數據也都應該實現 Send。對於 async_method,你需要確保它的返回類型 impl Future<Output = ()> 也實現了 Send。
tokio默认是启用多线程调度的,所以需要任务满足Send;如果想要单线程的话,需要自己手动指定一个单线程的调度策略
--
👇
缘罪: 我没搞懂这块为啥需要约束Send
感谢大佬耐心解答,我知道了
--
👇
TinusgragLin: > 我没搞懂这块为啥需要约束Send
哦,我知道了,你的疑惑是不是为啥 tokio::spawn 需要一个 Send 的 Future?
如果我理解没错的话,这是因为 tokio 的任务调度系统默认开了任务窃取,如果某个 worker 线程闲得发慌可以把其他 worker 线程任务队列中的 Future 给这个线程,所以需要 Future 的 ownership 可以在不同线程间转移,所以需要 Send 约束,字节有一个(为负载均衡任务设计的)monoio 异步运行时就没有这个要求了。
哦,我知道了,你的疑惑是不是为啥 tokio::spawn 需要一个 Send 的 Future?
如果我理解没错的话,这是因为 tokio 的任务调度系统默认开了任务窃取,如果某个 worker 线程闲得发慌可以把其他 worker 线程任务队列中的 Future 给这个线程,所以需要 Future 的 ownership 可以在不同线程间转移,所以需要 Send 约束,字节有一个(为负载均衡任务设计的)monoio 异步运行时就没有这个要求了。
学到了 https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=41b5bb02843224f46c7eb5fdedfe44e5
--
👇
TinusgragLin: 如果我记得没错的话,目前 trait 中的 async 方法返回的 Future 默认是没有 Send 约束的,不过现在 nightly 有了 return type notation 之后,就可以加一个这样的约束了:
把
改成
参考 https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#async-fn-in-public-traits
大概是因为现在 trait 中的 async 方法实际上跟这样写
差不多,返回值是一个“opaque type”(实际类型“隐藏”的类型),对于类型系统来说,这就是“某一个”实现了的 Future trait 的类型,而不会考虑它的实际类型,所以类型检查的时候会很保守。
之前官方的博客有一篇相关的文章,你可以参考一下。
我没搞懂这块为啥需要约束Send
--
👇
TinusgragLin: 如果我记得没错的话,目前 trait 中的 async 方法返回的 Future 默认是没有 Send 约束的,不过现在 nightly 有了 return type notation 之后,就可以加一个这样的约束了:
如果我记得没错的话,目前 trait 中的 async 方法返回的 Future 默认是没有 Send 约束的,不过现在 nightly 有了 return type notation 之后,就可以加一个这样的约束了: