Rust随笔(八)
今天来谈谈Rust里面的Sync和Send,在随笔七里面我们提到这两个概念,今天我们来详细的说一下。这两个trait是rust异步编程的主要基石之一。我们首先看看定义:
- Send
Send表示一个类型的所有权可以安全地在线程之间转移。 - Sync
Sync表示一个类型的不可变引用(&T)可以安全地在线程之间共享。 只有同时实现这两者,才能在多线程环境下共享数据,看着定义我们会感到有点疑惑,接下来我们用例子说明。
大约 13 分钟
今天来谈谈Rust里面的Sync和Send,在随笔七里面我们提到这两个概念,今天我们来详细的说一下。这两个trait是rust异步编程的主要基石之一。我们首先看看定义:
Send 表示一个类型的所有权可以安全地在线程之间转移。Sync 表示一个类型的不可变引用(&T)可以安全地在线程之间共享。
只有同时实现这两者,才能在多线程环境下共享数据,看着定义我们会感到有点疑惑,接下来我们用例子说明。我们前面介绍了Arc<Mutex<T>>这个东西,本篇我们以此为引子,打开Rust编程中异步编程的门。
几乎每一个编程语言都能做到异步编程,那么什么是异步编程呢?这里举一个例子:
n * (m + w + t),公式看起来不大,但是如果时间单位是秒,n是一个很大的数(比如说1百万),那么处理起来就很吓人了,从上面我们得到一个条件,就是每一件事情没有关联,那么我们就可以在处理这些事情的时候,在等待期间就可以做其他事情,那么按照这样的思路做,时间就变成了(n * m) + w + (n * t)(调度的时间在这里为了简化所以忽略不计),这样看时间是不是少了一个数量级,如果我们加多一些人手来做,假设添加了p个人,那么时间就变成了(n * (m + t)) / p + w,这样是不是又少了一个数量级。所以这个就是异步编程的核心思想:
协作式调度与非阻塞等待。任务在遇到需要等待的操作(如网络请求)时,会主动让出执行权,这样同一个工作线程就可以立刻去处理其他准备就绪的任务。这极大地提高了在 I/O 密集型场景下的资源利用率。
这里只是大致的描述一下异步编程,异步编程本身又非常多的概念,比如说并行,并发,同步,异步,资源调度等等。这些概念可以自行了解。接下来,我们介绍一下操作异步的基本单位:协程,与之相关的:线程和进程。我最早听到异步这个东西,是在写js获取api数据的时候,做完那个工作的时候,我知道了异步和同步的区别: 同步: 在一个进程内,有一部分的上下文在执行多个操作,在这里,这些操作必须完成之后才能执行下一步的操作,这种线性执行的模式就叫同步。 异步: 与同步相反,异步就是这部分的上下文中,有一个或多个操作,在执行这些操作时,将该操作建立起来之后就执行下一个操作,那么这个操作就叫异步。 以js为例子:
function asyncFunc(){
setTimeout(logsomething, 3000)
console.log("这是第二步")
}
function logsomething(){
console.log("这是第一步")
}
asyncFunc()
线程是操作操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位,一个进程内可以包含多个线程,线程是资源调度的最小单位。
因为Web服务和网路服务本身是 IO 密集型服务,处理的任务大多是和网络连接或读写相关的高耗时任务,因为IO本身是异步服务,所以在高并发场景下,大量 IO 等待会导致多线程被频繁挂起和切换,非常消耗系统资源,同时多线程访问共享资源存在竞争问题。如果将其升级为多进程,就会存在频繁调度切换问题以及每个进程资源不共享问题。所以在线程的基础上进一步切分,协程就诞生了,一个线程也可以拥有多个协程,因此协程又称微线程和纤程。