当子例程很昂贵时,为什么多线程执行不起作用? [重复]

问题描述 投票:0回答:1

此问题已经在这里有了答案:

此程序随机打印索引编号,例如1、4、2、3、100...。

use std::thread;

fn main() {
    for x in 0..100 {
        print!("{}: {:?} ", x, child.join());
    }
}

但是,一旦我添加了ping()函数,该函数除了执行控制台输出外,将不再并发执行,而是仅迭代ping()函数。

extern crate serde;
extern crate serde_derive;
extern crate reqwest;

use reqwest::Client;
use std::thread;
use std::process::Command;

fn main() {
    for x in 0..100 {
        let child = thread::spawn(move || {
            ping(x);
        });
        print!("{}: {:?} ", x, child.join());
    }
}

fn ping(x: i32) {
    let output = if cfg!(target_os = "windows") {
                    Command::new("cmd")
                        .args(&["/C", "echo hello"])
                        .output()
                        .expect("failed to execute process")
                 } else {
                     Command::new("sh")
                         .arg("-c")
                         .arg("https://keisugano.blogspot.com/")
                         .output()
                         .expect("failed to execute process")
                 };
    println!("{:?}", output);
}

此问题的根本原因是什么,我该如何解决?

multithreading concurrency rust
1个回答
2
投票

第一个示例是不完整的,没有实际产生线程,所以不确定那里发生了什么。

这里的关键点是join正在阻塞,这意味着在基础线程完成之前它不会返回。从the documentation

pub fn join(self) -> Result<T>

等待关联线程完成。

就原子内存顺序而言,相关线程的完成与此函数的返回同步。换句话说,该线程执行的所有操作在连接返回之后发生的所有操作之前被排序。

有了这些新知识,很明显您的代码实际上是在做:创建一个新线程,等待它完成,然后创建下一个线程。因此它仍然是顺序的,显然不是您想要的。

解决方案很简单:首先创建所有线程,然后等待它们完成,如下所示:

use std::thread;

fn main() {
    let handles = (0..100)
        .into_iter()
        .map(|x| {
            thread::spawn(move || {
                ping(x);
            })
        })
        .collect::<Vec<_>>();

    for thread in handles {
        thread.join().unwrap();
    }
}

fn ping(x: i32) {
    // Do things.
}
© www.soinside.com 2019 - 2024. All rights reserved.