Goroutine协程是什么

Goroutine是什么?

Goroutine是Go语言特有的名词。区别于进程Process,线程Thread,协程Coroutine,因为Go语言的创造者们觉得和他们是有所区别的,所以专门创造了Goroutine。

搞清楚Goroutine是什么首先要先清楚协程的概念

协程

协程是一种用户态的轻量级线程,协程的调度完全由用户控制,协程间切换只需要保存任务的上下文,没有内核的开销。

协程是编译器级别的,现在很多编程语言都支持协程,如 Erlang、Lua、Python、Golang。准确来说,协程只是一种用户态的轻量线程。

协程的优势

  • 内存占用少:线程栈空间通常是 2M,Goroutine 栈空间最小 2K;Golang 程序中可以轻松支持10w 级别的 Goroutine 运行,而线程数量达到 1k 时,内存占用就已经达到 2G。
  • 上下文切换代价小:Goroutine 上下文切换只涉及到三个寄存器(PC / SP / DX)的值修改;而对比线程的上下文切换则需要涉及模式切换(从用户态切换到内核态)、以及 16 个寄存器、PC、SP…等寄存器的刷新;
  • Go 协程使用信道(Channel)来进行通信。信道用于防止多个协程访问共享内存时发生竞态条件(Race Condition)。信道可以看作是 Go 协程之间通信的管道。我们会在下一教程详细讨论信道。

线程的出现,是为了分离进程的两个功能:资源分配和系统调度。让更细粒度、更轻量的线程来承担调度,减轻调度带来的开销。但线程还是不够轻量,因为调度是在内核空间进行的,每次线程切换都需要陷入内核,这个开销还是不可忽视的。协程则是把调度逻辑在用户空间里实现,通过自己(编译器运行时系统/程序员)模拟控制权的交接,来达到更加细粒度的控制。

 Goroutine

Goroutine是与其他函数或方法同时运行的函数或方法。Goroutines可以被认为是轻量级的线程。与线程相比,创建Goroutine的成本很小,它就是一段代码,一个函数入口。以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除)。因此它非常廉价,Go应用程序可以并发运行数千个Goroutines。

Goroutines在线程上的优势。
  1. 与线程相比,Goroutines非常便宜。它们只是堆栈大小的几个kb,堆栈可以根据应用程序的需要增长和收缩,而在线程的情况下,堆栈大小必须指定并且是固定的
  2. Goroutines被多路复用到较少的OS线程。在一个程序中可能只有一个线程与数千个Goroutines。如果线程中的任何Goroutine都表示等待用户输入,则会创建另一个OS线程,剩下的Goroutines被转移到新的OS线程。所有这些都由运行时进行处理,我们作为程序员从这些复杂的细节中抽象出来,并得到了一个与并发工作相关的干净的API。
  3. 当使用Goroutines访问共享内存时,通过设计的通道可以防止竞态条件发生。通道可以被认为是Goroutines通信的管道。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当我们需要进行并发编程时,通常会使用线程或进程来实现。但是,线程和进程的开销比较大,而且容易发生死锁、竞态条件等问题。Golang 提供了协程Goroutine)和通道(Channel)等并发机制,可以轻松实现高效的并发编程。 协程Goroutine)是一种轻量级线程,由 Golang 运行时管理。与线程相比,协程的开销非常小,可以轻松创建数以千计的协程,并发执行任务。协程之间通过通道(Channel)进行通信,以实现数据共享和同步。 通道(Channel)是一种特殊的数据类型,用于协程之间的通信。通道可以用于发送和接收数据,通道的发送和接收操作是原子性的,因此可以保证数据的同步和安全。通道有两种类型:有缓冲通道和无缓冲通道。有缓冲通道可以缓存一定数量的数据,但发送和接收操作可能会发生阻塞;无缓冲通道必须有发送和接收操作同时进行,否则会发生阻塞。 以下是一个简单的示例,演示了如何使用协程和通道实现并发处理任务: ```go func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Printf("worker %d started job %d\n", id, j) time.Sleep(time.Second) fmt.Printf("worker %d finished job %d\n", id, j) results <- j * 2 } } func main() { jobs := make(chan int, 100) results := make(chan int, 100) for w := 1; w <= 3; w++ { go worker(w, jobs, results) } for j := 1; j <= 5; j++ { jobs <- j } close(jobs) for r := 1; r <= 5; r++ { <-results } } ``` 在这个示例中,我们创建了一个有缓冲通道 `jobs` 和一个无缓冲通道 `results`。然后创建了 3 个协程 `worker`,用于处理任务。在 `main` 函数中,我们向 `jobs` 通道中发送了 5 个任务,然后关闭了 `jobs` 通道。接下来,我们从 `results` 通道中接收了 5 个结果。在 `worker` 函数中,我们使用 `range` 循环从 `jobs` 通道中接收任务,然后处理任务并将结果发送到 `results` 通道中。 通过协程和通道的组合,我们可以轻松实现并发处理任务,并且避免了线程和进程的开销和安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值