Rust的并发实现

sean 编辑于2023-11-03 09:34Rust

并行并发的介绍:
并行(parallelism):在多个核cpu下并行才有意义, 程序的不同部分,在多个cpu上同时运行,提高整体性能。
并发(concurrency): 把程序分解成相互独立的部分,以方便让每一个部分可以同时运行,不会互相影响,提高运行效率。在单核cpu中表现就是cpu的利用率很高。

进程线程概念介绍:
进程(process):程序通常是在进程中运行,由操作系统管理调度多个进程
线程(thread): 应用程序中,各个独立的部分可以同时运行,运行这些独立部分的就是线程

Rust并发实现方式:
1.通过操作系统的api来创建线程,1:1模型(rust标准库提供此模型的线程),一个操作系统的线程对应一个语言的线程。线程调度管理由操作系统完成,所以需要较小的运行时, 计算密集型的线程适合采用此方式建立线程。但当遇到io密集的线程操作会,导致性能急剧下降,这个适合可以考虑第二种异步协程模型来实现高并发。
2.Rust语言自己实现的异步协程:M:N模型,线程创建调度管理需要由程序自己实现,所以需要更大的运行时。比较适合io密集型的高并发需求。

多线程运行,会带来性能提升,但同时也会带来复杂性:
1.在竞争状态下,每个线程的执行的顺序无法保证,线程会以不一致的顺序访问数据或资源。可以通过信号量来解决但复杂度和性能会损失不少。
2.死锁, 两个线程彼此等待对方已使用完持有的资源,线程就无法继续运行。加入互斥锁可以解决,但会带性能损失
之前的通过信号量和互斥锁的大量使用带来了实现复杂度的提升,多线程的性能和安全问题,比如在特定条件下线程间的干扰导致的问题,有潜在的不稳定性,很难重现,不好被锁定和修复。

使用线程和通道解决并发问题。
1978年托尼.霍尔,提出使用队列(queue)或者通道(channel)将线程连接起来。线程实现类似进程的隔离过程,与其他线程间不共享内存(从内存安全的角度来看,有效避免了共享内存的使用从而降低了线程间干扰。)具体在rust标准库中,就是采用std::sync::mpsc::sync_channel/channel,从目前情况来看,使用线程和通道基本可以解决大部分程序的并发问题, 还可以结合Rayon库充分利用cpu多核优势实现程序的并行执行,很适合计算密集型的应用开发。

到这里,如果线程和通道模式已经解决了你的问题就不用再往后看了

线程不是越多越好:C10K问题
大量io(网络io或文件io)操作程序的并发,线程+通道模式并不能很好的解决这类问题,C10K问题的本质是每个线程的生成也是需要产生操作系统调度开销的,而每个线程多是io操作等待对于cpu计算需求并不大,这种情况产生的并发能力下降,但每个cpu核利用率并没有占满,大多的时候都是io等待。而线程的增多就会带来线程的上下文切换开销,当达到一个数量级的时候,这个开销就很可观了。目前可以通过以下两种方式解决:
1.将需要调度的任务,放到操作系统的线程池里, 让操作系统根据cpu的实际核心数来合理分配线程,来最大化实现程序的并行运行。
2.采用异步协程并发模型:任务在用户空间内部自己创建和管理,无需操作系统参与任务生成和调度。这样可以充分榨干每一个cpu核心,实现cpu资源的饱和利用。

rust异步协程:rust异步,实现一个io任务的执行后可以立即返回future或promise,无需阻塞等待,这样在编译时会出现引用传递和生命周期问题,需要采用Arc原子引用计数来解决生命周期。实际实现复杂度还是蛮大的,目前可以通过使用成熟的异步库为我们使用比如:tokio,mio

关于本站

肥龙软件分享的软件是本站作者开发的免费,无广告,安全可靠,绝不附带任何无关软件,绝不困绑任何插件的实用软件。如果您感觉好用,可以捐赠我们,这样我们可以有更积极的动力去改进升级软件,维持服务器运转,感谢您的捐助,谢谢!

致谢 赞赏/捐助名单

2024-8-13 **军 ¥16.8

更新时间:2024.8.31

联系作者(邮箱)
分类