作者:林冠宏 / 指尖下的幽灵

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities


目录

  • 前言
  • 协程
  • 协程的特点
    • 第 1第 2
    • 特点中的第 3 和 第 4 点
  • 和线程的整体对比

前言

国庆愉快各位,距离上次发文快两个月了,19年也快结束了。现在的总结更多是放在了草稿 而没有发出,这次详细分享下在 Go 中,线程和协程的区别及其关系

协程

协程,英文名Coroutine。但在 Go 语言中,协程的英文名是:gorutine。它常常被用于进行多任务,即并发作业。没错,就是多线程作业的那个作业。

虽然在 Go 中,我们不用直接编写线程之类的代码来进行并发,但是 Go 的协程却依赖于线程来进行。

下面我们来看看它们的区别。

线程的基础介绍,这里请自行网上搜索文章,因为关于线程的优秀介绍文章已经很多。

协程的特点

这里先直接列出线程的特点,然后从例子中进行解析。

  1. 多个协程可由一个或多个线程管理,协程的调度发生在其所在的线程中。
  2. 可以被调度,调度策略由应用层代码定义,即可被高度自定义实现。
  3. 执行效率高。
  4. 占用内存少。

上面第 1第 2

我们来看一个例子:

func TestGorutine(t *testing.T) {
runtime.GOMAXPROCS(1) // 指定最大 P 为 1,从而管理协程最多的线程为 1 个
wg := sync.WaitGroup{} // 控制等待所有协程都执行完再退出程序
wg.Add(2)
// 运行一个协程
go func() {
fmt.Println(1)
fmt.Println(2)
fmt.Println(3)
wg.Done()
}() // 运行第二个协程
go func() {
fmt.Println(65)
fmt.Println(66)
// 设置个睡眠,让该协程执行超时而被挂起,引起超时调度
time.Sleep(time.Second)
fmt.Println(67)
wg.Done()
}()
wg.Wait()
}

上面的代码片段跑了两个协程,运行后,观察输出的顺序是交错的。可能是:

65
66
1
2
3
67

意味着在执行协程A的过程中,可以随时中断,去执协程行B,协程B也可能在执行过程中中断再去执行协程A。

看起来协程A 和 协程B 的运行像是线程的切换,但是请注意,这里的 A 和 B 都运行在同一个线程里面。它们的调度不是线程的切换,而是纯应用态的协程调度

关于上述代码中,为什么要指定下面两行代码?

runtime.GOMAXPROCS(1)
time.Sleep(time.Second)

这需要您去看下 Go 的协程调度入门基础,请看我之前的另外一篇调度分析文章:

Go 的协程调度机制

如果不设置 runtime.GOMAXPROCS(1),那么程序将会根据操作系统的 CPU 核数而启动对应数量的 P,导致多个 M,即线程的启动。那么我们程序中的协程,就会被分配到不同的线程里面去了。为了演示,故设置数量 1,使得它们都被分配到了同一个线程里面,存于线程的协程队列里面,等待被执行或调度。

协程特点中的第 3 和 第 4 点。

  1. 执行效率高。
  2. 占用内存少。

因为协程的调度切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。调度发生在应用态而非内核态。

内存的花销,使用其所在的线程的内存,意味着线程的内存可以供多个协程使用。

其次协程的调度不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,所以执行效率比多线程高很多。

和线程的整体对比

比较的点 线程 协程
数据存储 内核态的内存空间 一般是线程提供的用户态内存空间
切换操作 操作最终在内核层完成,应用层需要调用内核层提供的 syscall 底层函数 应用层使用代码进行简单的现场保存和恢复即可
任务调度 由内核实现,抢占方式,依赖各种锁 由用户态的实现的具体调度器进行。例如 go 协程的调度器
语音支持程度 绝大部分编程语言 部分语言:Lua,Go,Python ...
实现规范 按照现代操作系统规范实现 无统一规范。在应用层由开发者实现,高度自定义,比如只支持单线程的线程。不同的调度策略,等等

Golang:线程 和 协程 的区别的更多相关文章

  1. python 进程、线程与协程的区别

    进程.线程与协程区别总结 - 1.进程是计算器最小资源分配单位 - 2.线程是CPU调度的最小单位 - 3.进程切换需要的资源很最大,效率很低 - 4.线程切换需要的资源一般,效率一般(当然了在不考虑 ...

  2. python基础===进程,线程,协程的区别(转)

    本文转自:http://blog.csdn.net/hairetz/article/details/16119911 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自 ...

  3. 写了一年golang,来聊聊进程、线程与协程

    本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star. 进程 在早期的单任务计算机中,用户一次只能提交一个作业,独享系统的全部资源,同时也只能干一件事 ...

  4. golang中最大协程数的限制(线程)

    golang中最大协程数的限制 golang中有最大协程数的限制吗?如果有的话,是通过什么参数控制呢?还是通过每个协程占用的资源计算? 通过channel控制协程数的就忽略吧. 以我的理解,计算机资源 ...

  5. Python协程与Go协程的区别二

    写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...

  6. 深入分析 Java、Kotlin、Go 的线程和协程

    前言 协程是什么 协程的好处 进程 进程是什么 进程组成 进程特征 线程 线程是什么 线程组成 任务调度 进程与线程的区别 线程的实现模型 一对一模型 多对一模型 多对多模型 线程的"并发& ...

  7. Python学习之路--进程,线程,协程

    进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Q ...

  8. Queue、进程、线程、协程

    参考博客地址 http://www.cnblogs.com/alex3714/articles/5230609.html 1.python GIL全局解释器锁 python调用的操作系统的原生线程,当 ...

  9. 11.python之线程,协程,进程,

    一,进程与线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行 ...

随机推荐

  1. 【Edu 67】 补题记录

    CF1187D. Subarray Sorting 想要把一个数x换到前面,x一定是小一点的值.由于B串是固定的,A串可调整,我们可以遍历B数组,对于B[i],找到对于在A数组的位子pos,判断1-p ...

  2. HDU- 3605 - Escape 最大流 + 二进制压位

    HDU - 3605 : acm.hdu.edu.cn/showproblem.php?pid=3605 题目: 有1e5的的人,小于10个的星球,每个星球都有容量,每个人也有适合的星球和不适合的星球 ...

  3. Different Integers 牛客网暑期ACM多校训练营(第一场) J 离线+线状数组或者主席树

    Given a sequence of integers a1, a2, ..., an and q pairs of integers (l 1, r1), (l2, r2), ..., (lq, ...

  4. MAMP 访问时显示文件列表

    原文链接:他叫自己MR张 背景 MAMP是Mac下的一个PHP+Nginx+MySQL的集成环境,支持多站点,不同版本PHP. 今天有人请教MAMP如何显示文件列表的问题,这里记录一下. 知识补充 一 ...

  5. 关于JQuery.form.js异步上传文件点滴

    好久没动代码了,前几天朋友委托我帮忙给做几个页面,其中有个注册带图片上传的页面.已之前的经验应该很快就能搞定,没想到的是搞了前后近一天时间.下面就说说异步上传的重要几个点,希望自己下次遇到此类问题的时 ...

  6. java多线程之ThreadPoolExecutor

    ThreadPoolExecutor类 简介   java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须 ...

  7. 在JSP页面用EL表达式获取数据

    <h4>获取域对象中的值</h4><%    request.setAttribute("name", "射雕英雄传");     ...

  8. HTML5为什么只需要写<!DOCTYPE HTML>?

    HTML4.01中的doctype需要对DTD进行引用,因为HTML4.01基于SGML.而HTML5不基于SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为.其中,SGM ...

  9. Zookeeper系列一:Zookeeper基础命令操作

    有些事不是努力就可以改变的,五十块的人民币设计的再好看,也没有一百块的招人喜欢. 前言 由于公司年底要更换办公地点,所以最近投了一下简历,发现面试官现在很喜欢问dubbo.zookeeper和高并发等 ...

  10. 数据可视化之3D中国

    本文链接:https://blog.csdn.net/zhai_865327/article/details/82983489 其实一般情况下2D平面地图就够用了,但是为了更加美观及突出效果,就需要3 ...