golang中协程与线程的区别

1、goroutine中栈的大小是动态变化的

每个os线程都有一个固定大小的栈内存(通常为2MB),栈内存用于保存在其他函数调用期间那些正在执行或临时暂停的函数中的局部变量。而goroutine在生命周期开始时只有一个很小的栈(通常为2KB),goroutine的栈不是固定大小的,它可以按需增大和缩小。所以goroutine能够更高效的使用栈空间。

2、goroutine调度

os线程是由操作系统内核调度的,所以控制权限从一个线程到另一个线程需要一次完整的上下文切换:即保存一个线程的状态到内存,再恢复另一个线程的状态,最后更新调度器的数据结构。考虑到内存局部性和内存的访问次数,还有访问内存所需的cpu周期数量的增加,这个操作是比较耗时的。go运行时包含一个自己的调度器,采用m:n调度的技术(复用/调度m个goroutine到n个os线程)。go调度器是由特定的go语言结构触发的,比如一个goroutine调用time.Sleep或被通道阻塞或对互斥量操作时,调度器会将这个goroutine设置为休眠模式,并运行其它goroutine。因为它不需要切换到内核中,所以调用一个goroutine比调度一个线程成本低很多。

3、GOMAXPROCS

go调度器使用GOMAXPROCS参数来确定需要使用多少个os线程来同时执行go代码。默认是机器上的cpu数量。正在休眠或者正被通道通信阻塞的goroutine不需要占用线程。阻塞在I/O和其它系统调用中或调用非go语言写的函数的goroutine需要一个独立的OS线程,这个线程不计算在GOMAXPROCS中。

4、goroutine没有标识

在大部分支持多线程的操作系统和编程语言里,当前线程都有一个独特的标识,它通常可以获取一个整数或者指针。这个特性可以轻松构建一个线程的局部存储,以线程标识为键值的map,这样每个线程都可以独立的使用这个map存储和获取值。goroutine没有提供可供程序员访问的标识,这是由设计决定的,因为线程局部存储有一种被滥用的倾向,导致函数的行为不仅取决于它的参数,还取决于运行它的线程标识。因此,在线程的标识需要改变的场景,这些函数的行为就会变的诡异莫测。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 进程时代 后来,现代化的计算机有了操作系统,每个程序都是一个进程,但是操作系统在一段时间只能运行一个进程,直到这个...
    大学渣PG阅读 1,948评论 0 1
  • 1、并发与并行 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。并发(concurren...
    lesline阅读 9,620评论 0 2
  • Goroutine是Go里的一种轻量级线程——协程。相对线程,协程的优势就在于它非常轻量级,进行上下文切换的代价非...
    witchiman阅读 4,909评论 0 9
  • 我们的程序是如何被运行的? 学习过操作系统的人,应该对进程和线程的模型都是有所了解的。按照我的理解:「进程」是操作...
    蔡欣圻阅读 2,911评论 1 7
  • 世界不美好,你却那么好 一 前一阵,为了庆祝我找到新工作,你又背着我偷偷摸摸的给我买了一个新款手机,差不多5000...
    一个码字汪的洪荒之力阅读 444评论 0 2