• 线程、协程、Goroutine的区别和联系


    线程与协程的区别

    1.  调度上的区别
      • 切换开销的区别
      • 线程太重,资源占用太高,频繁创建销毁会带来严重的性能问题;
      • 协程切换远比线程小

         2.  协程的好处:

      • 一个协程几乎就是一个普通的对象,因此可以放心阻塞,一旦阻塞那么让当前线程执行其他的协程(goroutine)

    goroutine和协程的区别

    1. goroutine是协程的go语言实现,相当于把别的语言的类库的功能内置到语言里。从调度上看,goroutine的调度开销远远小于线程调度开销。
    2. 不同的是:Golang在runtime,系统调用等多方面对goroutine调度进行了封装和处理,即goroutine不完全是用户控制,一定程度上由go运行时(runtime)管理,好处:当某goroutine阻塞时,会让出CPU给其他goroutine。

    线程和goroutine的区别

    1. OS的线程由OS内核调度,每隔几毫秒,一个硬件时钟中断发到CPU,CPU调用一个调度器内核函数。这个函数暂停当前正在运行的线程,把他的寄存器信息保存到内存中,查看线程列表并决定接下来运行哪一个线程,再从内存中恢复线程的注册表信息,最后继续执行选中的线程。这种线程切换需要一个完整的上下文切换:即保存一个线程的状态到内存,再恢复另外一个线程的状态,最后更新调度器的数据结构。某种意义上,这种操作还是很慢的。
    2. 从调度上讲,线程的调度由 OS 的内核完成;线程的切换需要CPU寄存器和内存的数据交换,在线程切换的过程中需要保存/恢复所有的寄存器信息,比如16个通用寄存器,PC(Program Counter),SP(Stack Pointer),段寄存器等等,从而切换不同的线程上下文。 其触发方式为 CPU时钟。而goroutine 的调度 则比较轻量级,由go自身的调度器完成;Go运行的时候包涵一个自己的调度器,这个调度器使用一个称为一个M:N调度技术,m个goroutine到n个os线程(可以用GOMAXPROCS来控制n的数量),Go的调度器不是由硬件时钟来定期触发的,而是由特定的go语言结构来触发的,他不需要切换到内核语境,所以调度一个goroutine比调度一个线程的成本低很多。其只关心当前go程序内协程的调度;触发方式为 go内部的事件,如文件和网络操作垃圾回收,time.sleep,通道阻塞,互斥量操作等。在同一个原生线程里,若当前goroutine不发生阻塞,那么不会主动让出CPU给其他同一线程的goroutine的。在go程序启动时,会首先创建一个特殊的内核线程sysmom,负责监控和调度。
    3. 从栈空间上,goroutine的栈空间更加动态灵活。每个OS的线程都有一个固定大小的栈内存,通常是2MB,栈内存用于保存在其他函数调用期间哪些正在执行或者临时暂停的函数的局部变量。这个固定的栈大小,如果对于goroutine来说,可能是一种巨大的浪费。作为对比goroutine在生命周期开始只有一个很小的栈,典型情况是2KB, 在go程序中,一次创建十万左右的goroutine也不罕见(2KB*100,000=200MB)。而且goroutine的栈不是固定大小,它可以按需增大和缩小,最大限制可以到1GB。
    4. goroutine没有一个特定的标识。在大部分支持多线程的操作系统和编程语言中,线程有一个独特的标识,通常是一个整数或者指针,这个特性可以让我们构建一个线程的局部存储,本质是一个全局的map,以线程的标识作为键,这样每个线程可以独立使用这个map存储和获取值,不受其他线程干扰。goroutine中没有可供程序员访问的标识,原因是一种纯函数的理念,不希望滥用线程局部存储导致一个不健康的超距作用,即函数的行为不仅取决于它的参数,还取决于运行它的线程标识。
  • 相关阅读:
    05 DDMS中logcat的使用
    04项目的目录结构分析与资源引用
    03 Android之我的第一个.hello world 程序
    关于myeclipse的有关操作
    jsp运行原理分析
    JSP简介
    prepareStatement与Statement的区别
    正则表达式
    过滤器的作用和用法
    剑指Offer--数值的整数次方
  • 原文地址:https://www.cnblogs.com/maji233/p/11044862.html
Copyright © 2020-2023  润新知