美文网首页
go和rust的协程模型

go和rust的协程模型

作者: wangjie_yy | 来源:发表于2019-12-31 14:35 被阅读0次

协程

协程是一种可以调度的计算单元,它和线程有很多相似的地方:可以被挂起和恢复,有自己的运行上下文。比较大的一个不同之处在于:协程的调度发生在用户态,由用户态程序来控制和管理,而线程则是由OS直接调度的。多个协程可以都在一个线程上运行,他们的运行过程是并发的,但并不能真正的并行执行。由协程调度程序来切换各个协程的运行,使它们表现得像同时在执行。

简单的说,协程就是轻量级的线程,使用协程的主要目的就和使用多线程的目的一样,提高程序的性能,增加cpu的使用率。

go语言中的协程模型

go语言被设计为天生支持协程,在代码中使用 go 关键字就能启动一个goroutinue,也就是协程。go的runtime两大主要职责:一个是垃圾回收,另一个就是调度协程。 go的协程调度模型可以称作GMP模型,其中:

  • G 表示 goroutinue,也就是协程
  • M 表示 os thread
  • P 表示调度上下文,每个M必须要先获取一个P,才能够开始执行G。

最初的调度模型中没有P的概念,在1.1版本后,go的调度器中引入了P,这么做主要是为了提升调度的性能,尽力的保证每个可运行的G都能够尽快运行。调度机制主要特点如下:

  • 每个P都有一个可运行的G队列
  • 另外有一个全局的可以运行G队列
  • M获取到P后,从P的运行队列中获取G来运行
  • 如果P本地的运行队列为空,则尝试从全局队列中获取G来运行
  • 如果全局的运行队列也为空,则尝试从其他P的运行队列中获取G

每个G运行的时间是由调度器来控制的,不会出现让某个G一直运行,而让其他G长时间的等待。如果M在运行G的时候发生了阻塞,比如block在某个系统调用,M则也会被阻塞住,P的本地队列会调度到其他M上执行。

P的数量可以通过GOMAXPROCS函数来设置,因为每个M对应一个P,因此这个函数也可以认为是设置了go程序最大的线程数量。(注意,M是可以大于P的,例如:一个M阻塞住了,那么正在运行的M数目还是和P的数目一样,这样总的M数目就大于P了。)

rust 中的协程模型

rust语言本身没有支持协程,它没有runtime,也就不能做调度,gc这样的事情。不过rust提供了一些定义好的trait,如Future,可以用来实现协程。在rust中使用协程主要是通过tokio 包,tokio是一个用于异步编程的包,它的实现包括一个task系统,一个runtime,以及异步编码的一些基本库。

在tokio中,可以认为task就是协程,由tokio runtime调度执行。task有两个非常重要的特点:

  • task不会阻塞,它是全异步的
  • task的执行不会被打断,也就是如果task不主动让出,是不会被切换走的

如果一个task中依赖了某个底层资源,runtime执行这个task的时候,根据底层资源是否ready,可以分为两种情况处理:1,底层资源已经ready,那么task可以立即返回需要的结果;2,底层资源还没有准备好,那么task返回NotReady,并再次进入调度队列。task系统此时会记录下这个task和相应底层资源的关系,等到底层资源ready后,会再次将task交给runtime来执行。

如果task中没有依赖底层资源,runtime执行这个task的时候,会立即返回结果。需要注意的是,如果task中的计算逻辑过重,占用cpu时间过长,会影响到其他task的执行。因为tokio的runtime没有给task分配执行时间片,而是会一直将这个task执行完成,这个过程中,其他的task可能会长时间得不到执行,这是一种非预期的情形。这也是为什么task中不能写太重的计算逻辑的原因。

在使用tokio时,可以选择使用哪种类型的runtime,主要有两种:local thread 和 threadpool,也就是单线程和多线程的区别。

对比

比较go和rust中的协程实现来看,go的协程模型相对来说更好理解,可以类比OS调度线程的机制。由于goroutinue是可以阻塞的,只要某个goroutinue阻塞了,就将剩余可运行的goroutinue调度到其他线程上执行。

而rust的tokio则是一个异步的执行框架,task是异步非阻塞的,并且task的执行不可抢占。它和nginx,libevent,redis的运行机制更相似,但多了task这个概念,整个调度的机制显得更复杂。

参考

http://morsmachine.dk/go-scheduler

https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw

https://tokio.rs/docs/internals/runtime-model/

相关文章

  • go和rust的协程模型

    协程 协程是一种可以调度的计算单元,它和线程有很多相似的地方:可以被挂起和恢复,有自己的运行上下文。比较大的一个不...

  • Go协程介绍

    参考自《go专家编程》Go协程所实现的是M:N的线程模型,M个协程运行在N个线程中。 1. MPG模型 Go协程中...

  • Go并发模型:并发协程chan的优雅退出

    Go并发模型:并发协程chan的优雅退出 go chan的使用

  • 煮泡面引发的Go协程之并发编程支持

    swoole有协程,Go也有。我们知道与PHP相比,使用swoole和Go除了进程模型不一样,其主要的协程特性是关...

  • 21. Go 协程

    21. Go 协程 Go 协程是什么? Go 协程是与其他函数或方法一起并发运行的函数或方法。Go 协程可以看作是...

  • Go并发编程实践

    Go语言最大的特点就是并发编程,它实现了一种基于协程的并发模型。轻量级的协程模型减少了线程模型的切换消耗,大大增加...

  • GO学习笔记(18) - 并发编程(1) - 理解gorouti

    目录 进程、线程与协程 并发模模型介绍 GO并发编程介绍 进程、线程与协程 进程和线程 进程是程序在操作系统中的一...

  • go的协程并发-channel消息机制

    go的协程并发-channel消息机制 方式一 方式二 go-协程实现方案汇总

  • Go语言——goroutine并发模型

    Go语言——goroutine并发模型 参考: Goroutine并发调度模型深度解析&手撸一个协程池 Golan...

  • 随笔33号20180930-go协程小tips

    启动一个新的协程时,协程的调用会立即返回。与函数不同,程序控制不会去等待 Go 协程执行完毕。在调用 Go 协程之...

网友评论

      本文标题:go和rust的协程模型

      本文链接:https://www.haomeiwen.com/subject/bsiboctx.html