许式伟的架构课
许式伟
七牛云CEO
立即订阅
20092 人已学习
课程目录
已更新 72 讲 / 共 77 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样成长为优秀的软件架构师?
免费
基础平台篇 (21讲)
01 | 架构设计的宏观视角
02 | 大厦基石:无生有,有生万物
03 | 汇编:编程语言的诞生
04 | 编程语言的进化
05 | 思考题解读:如何实现可自我迭代的计算机?
06 | 操作系统进场
07 | 软件运行机制及内存管理
08 | 操作系统内核与编程接口
09 | 外存管理与文件系统
10 | 输入和输出设备:交互的演进
11 | 多任务:进程、线程与协程
12 | 进程内协同:同步、互斥与通讯
13 | 进程间的同步互斥、资源共享与通讯
14 | IP 网络:连接世界的桥梁
15 | 可编程的互联网世界
16 | 安全管理:数字世界的守护
17 | 架构:需求分析 (上)
18 | 架构:需求分析 (下) · 实战案例
19 | 基础平台篇:回顾与总结
加餐 | 我看Facebook发币(上):区块链、比特币与Libra币
加餐 | 我看Facebook发币(下):深入浅出理解 Libra 币
桌面开发篇 (16讲)
20 | 桌面开发的宏观视角
21 | 图形界面程序的框架
22 | 桌面程序的架构建议
23 | Web开发:浏览器、小程序与PWA
24 | 跨平台与 Web 开发的建议
25 | 桌面开发的未来
26 | 实战(一):怎么设计一个“画图”程序?
27 | 实战(二):怎么设计一个“画图”程序?
28 | 实战(三):怎么设计一个“画图”程序?
29 | 实战(四):怎么设计一个“画图”程序?
30 | 实战(五):怎么设计一个“画图”程序?
31 | 辅助界面元素的架构设计
课外阅读 | 从《孙子兵法》看底层的自然法则
加餐 | 想当架构师,我需要成为“全才”吗?
32 | 架构:系统的概要设计
33 | 桌面开发篇:回顾与总结
服务端开发篇 (14讲)
34 | 服务端开发的宏观视角
35 | 流量调度与负载均衡
36 | 业务状态与存储中间件
37 | 键值存储与数据库
38 | 文件系统与对象存储
39 | 存储与缓存
40 | 服务端的业务架构建议
41 | 实战(一):“画图”程序后端实战
42 | 实战(二):“画图”程序后端实战
43 | 实战(三):“画图”程序后端实战
44 | 实战(四):“画图”程序后端实战
45 | 架构:怎么做详细设计?
46 | 服务端开发篇:回顾与总结
加餐 | 如何做HTTP服务的测试?
服务治理篇 (11讲)
47 | 服务治理的宏观视角
48 | 事务与工程:什么是工程师思维?
49 | 发布、升级与版本管理
50 | 日志、监控与报警
加餐 | 怎么保障发布的效率与质量?
51 | 故障域与故障预案
52 | 故障排查与根因分析
53 | 过载保护与容量规划
54 | 业务的可支持性与持续运营
55 | 云计算、容器革命与服务端的未来
56 | 服务治理篇:回顾与总结
架构思维篇 (9讲)
57 | 心性:架构师的修炼之道
用户故事 | 站在更高的视角看架构
58 | 如何判断架构设计的优劣?
59 | 少谈点框架,多谈点业务
60 | 架构分解:边界,不断重新审视边界
加餐 | 实战:“画图程序” 的整体架构
61 | 全局性功能的架构设计
62 | 重新认识开闭原则 (OCP)
63 | 接口设计的准则
许式伟的架构课
登录|注册

11 | 多任务:进程、线程与协程

许式伟 2019-05-21
你好,我是七牛云许式伟。
到现在为止,我们已经介绍了操作系统的存储管理:内存与外存;也已经介绍了输入与输出设备的管理。
当然,考虑到输入与输出设备属于人机交互范畴,我们主要会留到下一章 “桌面软件开发” 去详细介绍,这一章,我们仅概要地回顾输入与输出设备的需求演进过程。
CPU + 存储 + 输入与输出,软件开发最基础的内容基本上就都覆盖到了。 今天开始,我们就来聊一聊多任务。

多任务与执行体

多任务的需求是随处可见的。常见的场景,比如我们想边工作边听音乐;又或者我们需要跑一个后台监控程序,以报告随时可能发生的异常。
那么,怎么才能做到多任务?
我们先从物理层面看。最早期的 CPU 基本上都是单核的,也就是同一时间只能执行一条指令。尽管如此,大家可能都听过 “摩尔定律”,简单地说就是,每隔一年半到两年,同样的钱能买到的计算力能够翻一倍。
这当然不是什么严谨的物理学定律,更多的是一定历史时期下的经验之谈。早期 CPU 工艺的发展,基本上是通过提高电子元器件的密集程度实现的;但是电子元器件大小总归有个极限,不可能无限小下去。
那么怎么办?不能更小的话,那就横向多铺几个,一颗 CPU 多加几颗核心。这样多核技术就出现了。多核的意思是说,单核速度我提不上去了,多给你几个,价格一样。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《许式伟的架构课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(59)

  • Barry
    有一个小建议,能否再每篇文章的最后面预告一下,下一篇要讲的主题。这样我们跟着主题先思考,等看文章的时候就可以看到作者和自己的想法有什么出入和补充。更有利于吸收

    作者回复: 挺好的建议,多谢。下一节我们讲 “进程内协同:同步、互斥与通讯”。

    2019-05-21
    23
  • kirogiyi
    这才是真正的架构师课程,如果不具备这些基础知识,很难想象能够设计出好的软件系统架构。现在看到很多懂点技术和懂点产品的人自封为架构师,并没有去真正抓住软件架构的本质,实在感到有些汗颜。
    2019-05-21
    21
  • 一步
    对于协程的概念没有理解,协程不也是走系统调用吗?走系统调用不就是走到了系统内核态呢?后面任务调度,cpu执行指令

    作者回复: 协程不走系统调用。协程切换只是寄存器的保存和恢复,所以可以在用户态下自己来实现。

    2019-05-21
    18
  • Linuxer
    有一个疑问:协程属于用户态的线程,它跟线程之间怎么对应呢?协程之间也需要切换,那线程切换的那些成本它一样有啊,没想明白它的优势在哪

    作者回复: 从单位时间成本来说,有一定优势但也不会特别大。主要少掉的代价是从用户态到内核态再回到用户态的成本。这种差异类似于系统调用和普通函数调用的差异。因为高性能服务器上io次数实在太多了,所以单位成本上能够少一点,积累起来也是很惊人的。

    2019-05-21
    8
  • 王聪 Claire
    您好,问一下epoll的意义在于让线程数量变少,是指等待执行的线程变少了吗?是因为都登记然后才能执行的机制吗?还是其他原因呢?谢谢。

    作者回复: 如果用同步 io,那么每个并行 io 必然需要需要一个线程。epoll 在于让 io 等待都发生在相同的地方,相当于线程做了多路 io 复用。

    2019-05-24
    7
  • youyui
    想了解下协程如何操作寄存器切换CPU上下文的,有没有什么好的资料可以学习下

    作者回复: https://github.com/Tencent/libco

    2019-05-29
    6
  • 钱晟龙🐲龍🐉
    老师,我一直有个问题没理解到,计算机在做IO的时候会不会使用CPU,如果会怎样使用的? 阻塞IO阻塞的时候,也就是IO进行时,它对应的线程是否已经放弃了CPU的执行权? 或者老师建议我查阅什么书籍。。

    作者回复: 1、https://m.baidu.com/sf_edu_wenku/view/3210fec818e8b8f67c1cfad6195f312b3169ebe8
    2、是的,执行权会转移

    2019-05-29
    4
  • 行者
    不太理解协程的是怎么做到文中提到的两个优势的。只是看了一下python的协程,能理解它能减少执行体切换的时间成本(因为全在用户态中),但它的执行本质上就是串行执行呀,只是不同的子程序有了更多的入口而已,那怎么做到加速呢?

    作者回复: python的协程是比较狭义的,它只是一种编程模式,并不算执行体。你可以了解一下Go语言的goroutine。

    2019-05-23
    4
  • 大糖果
    那可以理解为如果操作系统把线程实现的足够灵活,轻便,就不需要协程这个机制了吗?

    作者回复: 我认为是这样

    2019-05-21
    4
  • 13601994625
    理论上协程可以做到的优化,线程都可以做到。为什么不在操作系统层去解决这个问题呢?

    作者回复: 但是操作系统太多了,语言适配操作系统易,反过来难

    2019-06-19
    3
  • 闫飞
    这里对NodeJS部分的引述有点小错误,它本身厉害的地方应该是争取了很多不想学习底层C/C++语言又喜欢得到高性能的"懒惰"的程序员。它的底层是由v8解释器和基于用户代码单事件循环调用的libev调度框架组成。

    可惜的是遇到复杂的事件循环堵死的情况,不理解这些底层原理的流水线JS程序员依然不能很快找到解决方案。碰到一些封装了第三方C库的运算复杂度高的代码,FFI接口反而隐藏了更大的问题。

    至于异步编程回调麻烦的问题,其实编程语言也在另外一个纬度上封装异步原语,通过promise/await等高级抽象缓解回调地狱困境。
    2019-06-06
    3
  • 老师,可以这样理解吗?因为时代背景久远,当初操作系统设计的线程,不太适应现在巨流量的互联网时代,在网络IO请求过高的情况下,性能开销太大,所以才出现了协程的概念,还有一些线程池的手段来弥补这个问题

    作者回复: 应对方式有两种:一种是经典的线程池+异步io,一种是基于协程的同步io。后者背后的原理也是线程池+异步io,只不过加上了协程的语法糖了。

    2019-07-29
    2
  • Sylh
    https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/

    官方文档里面的,我看就是说是多进程的

    作者回复: https://linux.cn/article-5681-1.html?pr
    你可以仔细看一下中文版的

    2019-05-28
    2
  • fjpcode
    多路IO复用: 让IO的等待都发生在相同的地方。 用了不少,今天才终于弄理解清楚为啥叫 '多路IO复用'。
    2019-05-25
    2
  • Geek_03056e
    有几个问题请教一下老师:
    1 cpu时间片运行执行体,选择执行体时,是cpu控制,还是操作系统控制?进程、线程、协程获得的概率是一样的吗?
    2 通过sh,cpu知道了进程的首地址,执行进程,这个线程是怎么执行的呢?
    3 文中提到网络服务器的存储是个共享状态,这个存储指哪些存储呢?

    作者回复: 1、文章中有表格,里面的调度方就是你说的控制方。不同执行体控制方不一样,调度算法不一样,概率也就不一样。
    2、线程知道函数地址就行,一样是入口。
    3、共享存储包括内存、数据库等等。

    2019-05-21
    2
  • 贾志猛
    感觉进程与子进程的关系还不是很清楚,如果父进程执行结束后,子进程会怎样?子进程结束后,父进程会怎样?

    作者回复: 不会相互影响

    2019-05-21
    2
    2
  • 韩春亮
    “在创建一个进程这个事情上,UNIX 偷了一次懒,用的是 fork(分叉)语义。所谓 fork,就是先 clone 然后再分支,父子进程各干各的。”这句话不太理解,希望老师帮忙指点一下

    作者回复: 可以查一下fork相关的资料,这个api很经典,有很多介绍材料

    2019-05-21
    2
  • Messi Curry
    古代将职业发展分为奴、徒、工、匠、师、家、圣,读老师的文章如同听推理故事,不断刺激大脑,激发思考,理通脉络,这才是真正的师!
    2019-06-02
    1
  • zzx10
    多任务需求,既可以单核系统上通过分时系统实现。也可以通过
    多核CPU、多核心运行不同程序实现

    任务可以抽象为执行体。执行体有三类:线程、进程、协程。
    实现任务切换核心在于:记录任务状态、以及切换任务
    记录任务状态:
    通过寄存器实现。同时保护模式下,需要通过寄存器切换内存地址映射表,改变内存地址使用
    切换任务:
    进程与线程主要靠操作系统切换,规则基于时钟中断
    协程需用户自己实现

    进程内创建子进程,通过fork父进程创建子进程实现后。此后父子进程相对独立。
    但是进程占用资源比较多,后期出现了在同一软件需要多任务,同时共享内存地址空间,于是线程产生了

    协程产生的主要是网络服务器的需要。协程仅作用于用户态,避免原先系统调用产生的开销。
    同时出现了多路复用技术。
    使用线程进行网络通信,有时间成本、空间成本

    协程主要需求:
    协程创建、执行权切换
    协程调度
    协程的同步、互斥与通讯
    协程系统调用封装
    协程堆栈大小的分配
    2019-05-28
    1
  • keshawn
    1. UNIX的fork API clone父进程,减少参数的传递。看起来和面向对象当初设计的继承一样,当初设计的时候觉得会简化编程,经过大量的实践之后会发现耦合越来越严重。
    2. 线程的设计是否成功不好评价,协程相比线程的改进主要有以下几点:
     1)堆栈按需增长(线程是否也能如此实现?)
     2)去除线程局部存储,线程之所以提供线程局部存储是为了减少参数传递吧(比如ThreadLocal)?
     3)调度方由操作系统内核变成了用户态,用户态实现上和操作系统内核要做的调度应该没太多本质区别,但是节省了系统调用的成本?
    2019-05-21
    1
收起评论
59
返回
顶部