- 主题:rust新手问一下
use tokio::task::yield_now;
use std::rc::Rc;
#[tokio::main]
async fn main() {
tokio::spawn(async {
let rc = Rc::new("hello");
// `rc` is used after `.await`. It must be persisted to
// the task's state.
yield_now().await;
println!("{}", rc);
});
}
这里为什么要求rc可send?
rc是堆栈变量在await切换时不是跟task一块移动的吗?
或者说这个task在切换时它的局部变量如何保持的?
发自「今日水木 on MRX-W29」
--
修改:txgx FROM 42.234.95.*
FROM 42.234.95.*
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.*
rc属于coroutine中的局部变量(栈变量),这个coroutine在执行到yield_now().await这句时会被suspend,suspend时会保存栈,也就是局部变量的值会保持。
这个coroutine后来某个时刻被resume时,会利用之前保存的栈继续执行,rc之前的值就继续用了。直到退出coroutine的scope时被drop/destroy。
这跟其他语言的coroutine没啥大区别: coroutine被suspend时保存栈(帧),coroutine被resume时恢复栈(帧)。
cpp的还有人给翻译了一下
https://bbs.huaweicloud.com/blogs/150492
--
FROM 114.241.227.*
大概是明白了,rust担心rc被其他人使用,所以用规则一棍子打死。
!send的不能穿越await
就是懒政。
实际上没有问题,rc只有一个owner.
【 在 ilovecpp 的大作中提到: 】
: tokio和你这个rc没有关系。
:
: 你的rc是async的状态(可以简单想像成stack frame)的一部分。只要任何一个状态是!Send,整个async就是!Send。
:
: 然后tokio::spawn:
: pub fn spawn<T>(task: T) ->
: ..................
发自「今日水木 on MRX-W29」
--
FROM 42.234.95.*
不是!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.*
再问一个问题, 这个怎么搞 ?
只是想 print vals 长度而已 , 编译不了
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals { // vals moved,
tx.send(val).unwrap();
//println!("Len in vec {:?}", vals.len()); // so invalide here!!
thread::sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {}", received);
}
}
【 在 ilovecpp 的大作中提到: 】
: 不是!Send不能穿越await,而是!Send的状态跨过await,会使得async fn变成!Send。
: 一个async fn是!Send本身没有任何问题,只是不满足tokio::spawn的要求。
: 就Rc而言,的确理论上可以在不同线程间传递,只要保证不同时访问即可。
: ...................
--
FROM 42.234.95.*
传给tx.send之前先clone到临时变量中,print那个临时变量
【 在 txgx 的大作中提到: 】
: 再问一个问题, 这个怎么搞 ?
: 只是想 print vals 长度而已 , 编译不了
:
: ...................
--
FROM 114.241.227.*
你看错了,tx.send的是,val,需要输出的是vals的长度。
vals被for拿走了。
【 在 z16166 的大作中提到: 】
: 传给tx.send之前先clone到临时变量中,print那个临时变量
: --
发自「今日水木 on MRX-W29」
--
FROM 42.234.95.*