- 主题:rust新手问一下
async不要求状态是Send。
这是tokio的要求。因为tokio可以选多线程模式,task执行和创建的线程可能不一样。
https://docs.rs/tokio/1.6.0/tokio/fn.spawn.html
【 在 txgx 的大作中提到: 】
: use tokio::task::yield_now;
: use std::rc::Rc;
: #[tokio::main]
: ...................
--
修改:ilovecpp FROM 58.37.58.*
FROM 101.82.205.*
tokio和你这个rc没有关系。
你的rc是async的状态(可以简单想像成stack frame)的一部分。只要任何一个状态是!Send,整个async就是!Send。
然后tokio::spawn:
pub fn spawn<T>(task: T) -> JoinHandle<T::Output> where
T: Future + Send + 'static,
T::Output: Send + 'static,
类型不匹配,仅此而已。
你要用!Send,可以spawn_local:
pub fn spawn_local<F>(future: F) -> JoinHandle<F::Output> where
F: Future + 'static,
F::Output: 'static,
【 在 txgx 的大作中提到: 】
: 对于tokio这个例子,当await的时候,它是怎么外理rc这个变量的?
: 发自「今日水木 on MRX-W29」
--
修改:ilovecpp FROM 58.37.58.*
FROM 58.37.58.*
不是!Send不能穿越await,而是!Send的状态跨过await,会使得async fn变成!Send。
一个async fn是!Send本身没有任何问题,只是不满足tokio::spawn的要求。
就Rc而言,的确理论上可以在不同线程间传递,只要保证不同时访问即可。
但这种运行时行为,编译器很难去证明。所以编译器完全禁止!Send传出当前线程。
另一方面,你既然用Rc,本身就说明它不太可能“只有一个owner”,否则用普通变量就行了。在真实的代码(而不是这种例子)中,用了Rc,一般来说它就会被传出当前async fn。
【 在 txgx 的大作中提到: 】
: 大概是明白了,rust担心rc被其他人使用,所以用规则一棍子打死。
: !send的不能穿越await
: 就是懒政。
: ...................
--
FROM 58.37.58.*
你想想send掉一个元素之后,vals里面有一个位置没有元素,是什么状态?
显然不可能是合法状态。就像你注释写的一样,vals已经被消费掉了,不能再访问了。
1. 你把对vals的访问移到for前面。
2. 像楼上说的,不要直接send元素,clone:
for val in &vals {
tx.send(val.clone()).unwrap();
或者
for val in vals.iter() {
tx.send(val.clone()).unwrap();
【 在 txgx 的大作中提到: 】
: 再问一个问题, 这个怎么搞 ?
: 只是想 print vals 长度而已 , 编译不了
:
: ...................
--
FROM 58.37.58.*
这个理解不对。Vec的into_iter不是通过“丢弃它的元素(缩小)”实现的。IntoIter拿走了原Vec的整个buffer,原Vec在into_iter之后直接消失。
数组没有into_iter只是rust编译器的技术限制,没有什么原理上的困难。相关代码上个月刚刚加入,rust下个版本里数组应该可以直接for in了。
【 在 z16166 的大作中提到: 】
: self的ownership发生了转移,所以是mut self。
: 可以改用for val in vals.iter()这个,iter()是ref,不是mut ref,这样for循环里面可以继续使用vals。
: "Rust 中的集合(Collection)提供三个公共方法创建迭代器:iter()、iter_mut() 和 into_iter(),分别用于迭代 &T(引用)、&mut T(可变引用)和 T(值)。其中,前两种是普通方法,而into_iter() 来自于 IntoIterator trait。Rust 的 for 循环其实是迭代器语法糖,当没有显式的使用迭代器时,它会根据不同的上下文,分别使用 T、&T 和 &mut T 类型所实现的 into_iter() 返回的迭代器。唯一的例外是数组,原因是数组不能丢弃它的元素(不能缩小),因此 [T; N] 类型无法实现 into_iter(),只有 &[T; N] 和 &mut [T; N] 类型实现了 into_iter()。"
: ...................
--
修改:ilovecpp FROM 58.37.58.*
FROM 58.37.58.*
你引用的链接已经告诉你了:
let closure: Box<FnMut() + Send + 'env> = Box::new(closure);
let closure: Box<FnMut() + Send + 'static> = unsafe { mem::transmute(closure) };
mem::transmute相当于C++的reinterpret_cast,强制类型转换。你把'env的lifetime强制转成'static,自然可以传给任何人。不过你要自己保证实际使用closure的时间不能超过'env。
你不需要向编译器证明unsafe代码的正确性。unsafe其实是把编译器证不过去的步骤,直接写成一个公理。
跟做证明题的时候,证不过去的地方写“显然”差不多。有些人写“显然”是真的想得很清楚。有些人则是证明一卡住就“显然”过去。像后面这样写rust的人好像也不少。
【 在 z16166 的大作中提到: 】
: 嗯,crossbeam这个例子正好解决了问题。
: 而且要跨线程传栈变量的引用基本只能用这种范式了,不知道这东西的会卡在这里好久。
: 不过下一个问题来了:
: ...................
--
修改:ilovecpp FROM 58.37.58.*
FROM 58.37.58.*