< 返回版块

mu0641 发表于 2021-03-10 10:50

#[async_std::main]
async fn main()  -> io::Result<()> {

    let mut coll = Vec::with_capacity(1000000);
    for i in 0..1000000{
        coll.push(String::from("xxxxxxxxxxxxxx"));
    }

    let chs = coll.chunks(50000);
    let mut fus = Vec::new();
    for ch in chs{
        let f = spawn(async move{
                    println!("{}", ch.len());
        });  
       fus.push(f);
    }

    for f in fus{
        f.await
    }
}

上面这版编译会报错

#[async_std::main]
async fn main()  -> io::Result<()> {

    let page = 50000;

    let mut coll = Vec::with_capacity(1000000);
    for _i in 0..1000000{
        coll.push(String::from("xxxxxxxxxxxxxx"));
    }
    let mut fus = Vec::new();
    let acoll = Arc::new(coll);
    let chs = acoll.chunks(50000);

    for i in 0..chs.len(){
        let c_acoll = acoll.clone();
        let f = spawn(async move{
                    println!("{}", c_acoll[i*page..(i+1)*page].len());
        });  
       fus.push(f);
    }

    for f in fus{
        f.await;
    }

}

这里有什么更好的写法吗? spawn里面标记了边界'static,有种情况是不是只要是move进去的对象里面有借用的数据并且不是static生命周期的,那都没办法编译

比如:

struct Hi<'a>{
    a:&'a String
}

这种实例对象就没办法move进去了,这样写起来感觉好难

评论区

写评论
fakeshadow 2021-03-11 06:24

在main可以直接leak或者transmute一下生命周期。 但实际代码中不会是那么简单就在main里spawn一下。你很可能要在spawn中spawn,这时候借用就不是那么简单了。

ooopSnake 2021-03-10 14:05

你把所有的futures都收集起来了,然后await


for it in chk {
    let batch = Batch::new(it);
    let f = tokio::spawn(async move {
        ...
    });
    // future(JoinHandle)被收集
    fus.push(f);
}

...

async fn main(){
    ... // 省略
    for f in fus {
        f.await.unwrap()
    }
}

上面是从你代码里摘取的,大体意思是: 如果有async fn没有执行完,async main函数就会一直block,并不会立即执行完. 所以不会出现UAF漏洞

--
👇
mu0641: 这样写会有安全问题吧,如果main运行到底部,引用的数据已被释放,但是异步的线程还在执行

作者 mu0641 2021-03-10 13:55

这样写会有安全问题吧,如果main运行到底部,引用的数据已被释放,但是异步的线程还在执行

--
👇
ooopSnake: 办法有,不过得请出unsafe

#[derive(Debug)]
struct Batch {
    part: *const String,
    len: usize,
}

unsafe impl Send for Batch {}

impl Batch {
    fn new(part: &[String]) -> Batch {
        Batch {
            part: part.as_ptr(),
            len: part.len(),
        }
    }

    fn get_part<'a>(&self) -> &'a [String] {
        unsafe {
            std::slice::from_raw_parts(self.part, self.len)
        }
    }
}


#[tokio::main]
async fn main() {
    let mut coll = Vec::with_capacity(10);
    for i in 0..10 {
        coll.push(format!("i:{}", i));
    }
    let chk = coll.chunks(3);
    let mut fus = Vec::new();
    for it in chk {
        let batch = Batch::new(it);
        let f = tokio::spawn(async move {
            for (idx, value) in batch.get_part().iter().enumerate() {
                println!("idx:{},value:{}", idx, value)
            }
            ()
        });
        fus.push(f);
    }
    for f in fus {
        f.await.unwrap()
    }
}
作者 mu0641 2021-03-10 13:55

这样写会有安全问题吧,如果main运行到底部,引用的数据已被释放,但是异步的线程还在执行

--
👇
ooopSnake: 办法有,不过得请出unsafe

#[derive(Debug)]
struct Batch {
    part: *const String,
    len: usize,
}

unsafe impl Send for Batch {}

impl Batch {
    fn new(part: &[String]) -> Batch {
        Batch {
            part: part.as_ptr(),
            len: part.len(),
        }
    }

    fn get_part<'a>(&self) -> &'a [String] {
        unsafe {
            std::slice::from_raw_parts(self.part, self.len)
        }
    }
}


#[tokio::main]
async fn main() {
    let mut coll = Vec::with_capacity(10);
    for i in 0..10 {
        coll.push(format!("i:{}", i));
    }
    let chk = coll.chunks(3);
    let mut fus = Vec::new();
    for it in chk {
        let batch = Batch::new(it);
        let f = tokio::spawn(async move {
            for (idx, value) in batch.get_part().iter().enumerate() {
                println!("idx:{},value:{}", idx, value)
            }
            ()
        });
        fus.push(f);
    }
    for f in fus {
        f.await.unwrap()
    }
}
ooopSnake 2021-03-10 13:39

办法有,不过得请出unsafe

#[derive(Debug)]
struct Batch {
    part: *const String,
    len: usize,
}

unsafe impl Send for Batch {}

impl Batch {
    fn new(part: &[String]) -> Batch {
        Batch {
            part: part.as_ptr(),
            len: part.len(),
        }
    }

    fn get_part<'a>(&self) -> &'a [String] {
        unsafe {
            std::slice::from_raw_parts(self.part, self.len)
        }
    }
}


#[tokio::main]
async fn main() {
    let mut coll = Vec::with_capacity(10);
    for i in 0..10 {
        coll.push(format!("i:{}", i));
    }
    let chk = coll.chunks(3);
    let mut fus = Vec::new();
    for it in chk {
        let batch = Batch::new(it);
        let f = tokio::spawn(async move {
            for (idx, value) in batch.get_part().iter().enumerate() {
                println!("idx:{},value:{}", idx, value)
            }
            ()
        });
        fus.push(f);
    }
    for f in fus {
        f.await.unwrap()
    }
}
1 共 5 条评论, 1 页