编程 Rust 并发执行异步操作

2024-11-19 08:16:42 +0800 CST views 665

Rust 并发执行异步操作

在 Rust 中,并发执行异步操作可以显著提升程序性能。本文将深入探讨两种常见的并发策略:多线程Futures 联合

多线程概述

线程本质上是 CPU 执行的一段软件代码序列。我们可以将其理解为一个运行进程的容器。多线程允许我们同时运行多个任务,从而提高程序性能,但同时也引入了复杂性。

创建和管理线程

使用 std::thread::spawn 函数可以创建新的线程:

use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        for i in 1..100 {
            println!("{} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

这段代码创建了一个新的线程,并在其中执行一个循环,打印数字并休眠。主线程也执行一个类似的循环。

Join 线程

主线程结束时,所有子线程都会被强制关闭,无论它们是否已完成任务。为了确保子线程完成,我们可以使用 JoinHandle 将子线程的返回值绑定到一个变量,并使用 join 方法等待子线程完成。

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("{} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("{} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().expect("error joining");
}

Join 线程的位置

join 方法的位置至关重要。如果将 join 方法放在主线程循环之前,主线程将等待子线程完成后再执行。

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("{} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });
    handle.join().expect("error joining");

    for i in 1..5 {
        println!("{} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

从 JoinHandle 获取返回值

通过 JoinHandle 获取子线程的返回值,例如:

fn main() {
    let handle_1 = thread::spawn(|| {
        for i in 1..10 {
            println!("{} from the spawned thread 1!", i);
            thread::sleep(Duration::from_millis(1));
        }
        100
    });

    let handle_2 = thread::spawn(|| {
        for i in 1..10 {
            println!("{} from the spawned thread 2!", i);
            thread::sleep(Duration::from_millis(1));
        }
        200
    });

    let result_1 = handle_1.join().expect("error joining");
    let result_2 = handle_2.join().expect("error joining");

    println!("final result: {} from the main thread!", result_1 + result_2);
}

使用 move 关键字

如果闭包需要获取外部变量的所有权,可以使用 move 关键字:

fn main() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(move || {
        println!("vector: {:?}", v);
    });

    handle.join().expect("error joining");
}

异步操作与多线程

使用 tokio::spawn 创建异步线程

tokio::spawn 可以用来创建异步线程:

use std::{thread, time::Duration};
use tokio;

#[tokio::main]
async fn main() {
    let spawn_1 = tokio::spawn(async {
        for i in 1..5 {
            println!("{} from the thread 1!", i);
            thread::sleep(Duration::from_millis(1));
        }  
    });

    let spawn_2 = tokio::spawn(async {
        for i in 1..5 {
            println!("{} from the thread 2!", i);
            thread::sleep(Duration::from_millis(1));
        }  
    });

    spawn_1.await.expect("error awaiting");
    spawn_2.await.expect("error awaiting");
}

tokio::spawn 创建的异步任务可能在当前线程或其他线程上执行,具体取决于运行时的配置。

Futures 联合

顺序执行 Futures

异步函数返回 Future 类型,可以使用 await 获取结果:

#[tokio::main]
async fn main() {
    let start = Instant::now();

    let future_1 = async_operation(1);
    let future_2 = async_operation(2);
    future_1.await;
    future_2.await;

    println!("{}: {:?}", "futures: ", start.elapsed());
}

async fn async_operation(thread: i8) {
    for i in 1..5 {
        println!("{} from the operation {}!", i, thread);
        tokio::time::sleep(Duration::from_millis(400)).await;
        thread::sleep(Duration::from_millis(100));
    }
}

并发执行 Futures

为了并发执行异步操作,可以使用 futures::future::join_all

#[tokio::main]
async fn main() {
    let start = Instant::now();

    let future_1 = async_operation(1);
    let future_2 = async_operation(2);
    join_all([future_1, future_2]).await;

    println!("{}: {:?}", "futures: ", start.elapsed());
}

总结

多线程 vs Futures 联合

  • 多线程:适合长时间运行的独立、内存或 CPU 密集型任务。
  • Futures 联合:适合短时间运行、依赖 IO 操作或无需返回值的任务。

选择合适的并发策略

在选择并发策略时,需要考虑任务的类型、依赖关系、资源限制等。

希望本文能够帮助您更好地理解 Rust 中的并发编程,并选择合适的策略来提高您的程序性能。


复制全文 生成海报 编程 Rust 并发编程 异步编程 性能优化

推荐文章

Vue3中的v-bind指令有什么新特性?
2024-11-18 14:58:47 +0800 CST
PHP来做一个短网址(短链接)服务
2024-11-17 22:18:37 +0800 CST
Nginx 实操指南:从入门到精通
2024-11-19 04:16:19 +0800 CST
Golang 随机公平库 satmihir/fair
2024-11-19 03:28:37 +0800 CST
Vue中如何处理异步更新DOM?
2024-11-18 22:38:53 +0800 CST
从Go开发者的视角看Rust
2024-11-18 11:49:49 +0800 CST
地图标注管理系统
2024-11-19 09:14:52 +0800 CST
html夫妻约定
2024-11-19 01:24:21 +0800 CST
使用Vue 3和Axios进行API数据交互
2024-11-18 22:31:21 +0800 CST
MySQL 主从同步一致性详解
2024-11-19 02:49:19 +0800 CST
php 统一接受回调的方案
2024-11-19 03:21:07 +0800 CST
HTML5的 input:file上传类型控制
2024-11-19 07:29:28 +0800 CST
html一些比较人使用的技巧和代码
2024-11-17 05:05:01 +0800 CST
Redis函数在PHP中的使用方法
2024-11-19 04:42:21 +0800 CST
html流光登陆页面
2024-11-18 15:36:18 +0800 CST
php机器学习神经网络库
2024-11-19 09:03:47 +0800 CST
Python 获取网络时间和本地时间
2024-11-18 21:53:35 +0800 CST
php内置函数除法取整和取余数
2024-11-19 10:11:51 +0800 CST
使用xshell上传和下载文件
2024-11-18 12:55:11 +0800 CST
程序员茄子在线接单