Multithreading 康威';使用多线程后,s的生活游戏变得更慢

Multithreading 康威';使用多线程后,s的生活游戏变得更慢,multithreading,rust,conways-game-of-life,Multithreading,Rust,Conways Game Of Life,我是一个铁锈的完全初学者,我目前正在写这个平行康威的生活游戏。代码本身工作正常,但问题是当使用多个线程时,程序会变慢(我通过计算滑翔机从左上角移动到右下角的时间来测量程序的速度)。我做了一些实验,随着线程数量的增加,它变得越来越慢。我还有一个Java版本,使用几乎相同的算法;它很好用。我所期望的是,如果线程不止一个,Rust版本至少可以稍微快一点。谁能指出我哪里做错了?如果代码看起来不合理,我很抱歉,因为我说过我是一个完全的初学者:-) main.rs读取命令行参数并执行板更新 extern c

我是一个铁锈的完全初学者,我目前正在写这个平行康威的生活游戏。代码本身工作正常,但问题是当使用多个线程时,程序会变慢(我通过计算滑翔机从左上角移动到右下角的时间来测量程序的速度)。我做了一些实验,随着线程数量的增加,它变得越来越慢。我还有一个Java版本,使用几乎相同的算法;它很好用。我所期望的是,如果线程不止一个,Rust版本至少可以稍微快一点。谁能指出我哪里做错了?如果代码看起来不合理,我很抱歉,因为我说过我是一个完全的初学者:-)

main.rs读取命令行参数并执行板更新

extern crate clap;
extern crate termion;
extern crate chrono;

use std::thread;
use std::sync::Arc;
use chrono::prelude::*;


mod board;
mod config;

use board::Board;
use config::Config;

fn main() {
    let dt1 = Local::now();

    let matches = clap::App::new("conway")
        .arg(clap::Arg::with_name("length")
            .long("length")
            .value_name("LENGTH")
            .help("Set length of the board")
            .takes_value(true))
        .arg(clap::Arg::with_name("threads")
            .long("threads")
            .value_name("THREADS")
            .help("How many threads to update the board")
            .takes_value(true))
        .arg(clap::Arg::with_name("display")
            .long("display")
            .value_name("DISPLAY")
            .help("Display the board or not")
            .takes_value(true))
        .arg(clap::Arg::with_name("delay")
            .long("delay")
            .value_name("MILLISECONDS")
            .help("Delay between the frames in milliseconds")
            .takes_value(true))
        .get_matches();

    let config = Config::from_matches(matches);
    let mut board = Board::new(config.length);
    let mut start: bool = false;
    let mut end: bool = false;
    let mut start_time: DateTime<Local> = Local::now();
    let mut end_time: DateTime<Local>;

    board.initialize_glider();
    loop {
        if config.display == 1 {
            print!("{}{}", termion::clear::All, termion::cursor::Goto(3, 3));
            board_render(&board);
        }

        if board.board[0][1] == 1 && !start {
            start_time = Local::now();
            start = true;
        }
        if board.board[config.length - 1][config.length - 1] == 1 && !end {
            end_time = Local::now();
            println!("{}", end_time - start_time);
            end = true;
        }

        board = board::Board::update(Arc::new(board), config.threads);
        thread::sleep(config.delay);
    }
}

fn board_render(board: &Board) {
    let mut output = String::with_capacity(board.n * (board.n + 1));
    for i in 0..board.n {
        for j in 0..board.n {
            let ch;
            if board.board[i][j] == 0 {
                ch = '░';
            } else {
                ch = '█';
            }
            output.push(ch);
        }
        output.push_str("\n  ");
    }
    print!("{}", output);
}

extern板条箱clap;
外部板条箱术语;
外部板条箱时钟;
使用std::线程;
使用std::sync::Arc;
使用chrono::前奏::*;
模块板;
mod config;
使用board::board;
使用config::config;
fn main(){
设dt1=Local::now();
让matches=clap::App::new(“康威”)
.arg(clap::arg::with_name(“长度”)
.long(“长度”)
.value_name(“长度”)
.help(“设置板的长度”)
.takes_值(true))
.arg(clap::arg::with_name(“threads”)
.long(“线程”)
.value_名称(“线程”)
.help(“要更新板的线程数”)
.takes_值(true))
.arg(clap::arg::with_name(“display”)
.long(“显示”)
.value_name(“显示”)
.help(“是否显示板”)
.takes_值(true))
.arg(clap::arg::with_name(“延迟”)
.long(“延迟”)
.value_name(“毫秒”)
.help(“帧之间的延迟,以毫秒为单位”)
.takes_值(true))
.get_matches();
让config=config::from_匹配(匹配);
让mut board=board::new(config.length);
让mut启动:bool=false;
让mut结束:bool=false;
让mut start_time:DateTime=Local::now();
让mut结束时间:DateTime;
板。初始化滑翔机();
环路{
如果config.display==1{
打印!(“{}{}”,termion::clear::All,termion::cursor::Goto(3,3));
线路板(渲染和线路板);
}
如果board.board[0][1]==1&&!启动{
开始时间=本地::现在();
开始=真;
}
如果board.board[config.length-1][config.length-1]==1&&!结束{
结束时间=本地::现在();
println!(“{}”,结束时间-开始时间);
结束=真;
}
线路板=线路板::线路板::更新(弧::新建(线路板),配置线程);
线程::睡眠(config.delay);
}
}
fn线路板渲染(线路板:&线路板){
让mut output=String::具有_容量(board.n*(board.n+1));
因为我在0.board.n{
对于0..board.n中的j{
让我们一起去吧;
如果board.board[i][j]==0{
陈冯富珍░';
}否则{
陈冯富珍█';
}
输出推力(ch);
}
output.push_str(“\n”);
}
打印!(“{}”,输出);
}
board.rs是使用多线程更新电路板的算法所在

use std::sync::{Mutex, Arc};
use std::thread;

pub struct Board {
    pub n: usize,
    pub board: Vec<Vec<i32>>,
}

impl Board {
    pub fn new(n: usize) -> Board {
        let board = vec![vec![0; n]; n];
        Board {
            n,
            board,
        }
    }

    pub fn update(Board: Arc<Self>, t_num: usize) -> Board {
        let new_board = Arc::new(Mutex::new(Board::new(Board.n)));
        let mut workers = Vec::with_capacity(t_num);

        let block_size = Board.n / t_num;
        let mut start = 0;

        for t in 0..t_num {
            let old_board = Board.clone();

            let new_board = Arc::clone(&new_board);
            let mut end = start + block_size;

            if t == t_num - 1 { end = old_board.n; }

            let worker = thread::spawn(move || {
                let mut board = new_board.lock().unwrap();
                for i in start..end {
                    for j in 0..old_board.n {
                        let im = (i + old_board.n - 1) % old_board.n;
                        let ip = (i + 1) % old_board.n;
                        let jm = (j + old_board.n - 1) % old_board.n;
                        let jp = (j + 1) % old_board.n;
                        let sum = old_board.board[im][jm] + old_board.board[im][j]
                            + old_board.board[im][jp] + old_board.board[i][jm] + old_board.board[i][jp]
                            + old_board.board[ip][jm] + old_board.board[ip][j] + old_board.board[ip][jp];

                        if sum == 2 {
                            board.board[i][j] = old_board.board[i][j];
                        } else if sum == 3 {
                            board.board[i][j] = 1;
                        } else {
                            board.board[i][j] = 0;
                        }
                    }
                }
            });

            workers.push(worker);
            start = start + block_size;
        }

        for worker in workers {
            worker.join().unwrap();
        }


        let result = new_board.lock().unwrap();
        let mut board = Board::new(Board.n);
        board.board = result.board.to_vec();

        board
    }

    pub fn initialize_glider(&mut self) -> &mut Board {
        self.board[0][1] = 1;
        self.board[1][2] = 1;
        self.board[2][0] = 1;
        self.board[2][1] = 1;
        self.board[2][2] = 1;

        self
    }
}
使用std::sync::{Mutex,Arc};
使用std::线程;
酒吧结构板{
酒吧n:使用,
酒吧董事会:Vec,
}
impl板{
新酒吧(n:usize)->董事会{
让board=vec![vec![0;n];n];
董事会{
N
板
}
}
发布fn更新(板:弧,t_num:usize)->板{
让new_board=Arc::new(Mutex::new(board::new(board.n));
让mut-workers=Vec::具有_容量(t_-num);
让block_size=Board.n/t_num;
让mut start=0;
对于0中的t..t_num{
让old_board=board.clone();
让新电路板=Arc::克隆(&新电路板);
让mut end=开始+块大小;
如果t==t_num-1{end=old_board.n;}
让worker=thread::spawn(移动| |){
让mut board=new_board.lock().unwrap();
因为我在开始…结束{
对于0.中的j.旧板{
设im=(i+old_board.n-1)%old_board.n;
设ip=(i+1)%old_board.n;
设jm=(j+old_-board.n-1)%old_-board.n;
设jp=(j+1)%old_board.n;
设sum=old_board.board[im][jm]+old_board.board[im][j]
+老董事会[im][jp]+老董事会[i][jm]+老董事会[i][jp]
+董事会[ip][jm]+董事会[ip][j]+董事会[ip][j]+董事会[ip][jp];
如果总和=2{
board.board[i][j]=旧董事会.board[i][j];
}如果总和=3,则为else{
董事会.董事会[i][j]=1;
}否则{
董事会.董事会[i][j]=0;
}
}
}
});
工人。推(工人);
开始=开始+块大小;
}
工人中的工人{
worker.join().unwrap();
}
让结果=new_board.lock().unwrap();
让mut board=board::new(board.n);
board.board=结果.board.to_vec();
板
}
发布fn初始化滑翔机(&mut self)->&mut板{
self.board[0][1]=1;
自选董事会[1][2]=1;
自选董事会[2][0]=1;
自选董事会[2][1]=1;
自选董事会[2][2]=1;
自己
}
}

每个工作线程在启动时都会立即尝试锁定互斥锁,并且在锁定完成之前不会释放该锁。由于一次只有一个线程可以保存互斥体,因此一次只有一个线程可以执行工作

以下是解决此问题的两种方法: