本人做了一个动态流程图的网页,能像ppt动画一样,通过不断点击出现流程图的每一项,从而达到动态。由于ui用的是drawio的ui,所以该动态流程图既美观,而且方便制作流程图,然后又能实现ppt通过点击出现元素的功能。
下图的图解的动态流程图地址:(出现元素后,需要等待两秒,元素消失后,即可通过不断点击出现元素)
http://43.138.251.145:2335/drawio/Golang%E7%9A%84GMP.html
用户级上下文:
寄存器上下文:此刻的各种寄存器的数据,比如pc寄存器保存着下一条要执行的指令。
系统级上下文:进程控制块、内存信息等
IO操作:内存、磁盘、网络、外设的输入和输出,耗时却不需要cpu
线程切换:
线程切换只涉及寄存器上下文。
当在单核cpu上运行的线程三切换到线程一时:
需要保存线程三此刻的上下文(比如程序运行到哪一条语句),
然后加载上一次运行线程一的上下文,执行线程一的任务
最终目的:榨干cpu的计算时间,为此,不能把这时间浪费在io操作、线程切换、空闲。
cpu单核:计算用
并行编程:利用多个cpu单核执行多个任务
并发编程:在单核(伪)上,运行多个任务。如果是用户态线程就是单核、如果是内核态线程就是多核
并发编程的作用:我们只讨论->为了不将cpu时间浪费在io操作
多线程:
问题**:**如果此刻线程三的任务很紧急怎么办,那么操作系统会把线程三放入队列的第一位,这样线程三就能提前执行任务
抢占式调度**:**操作系统会根据每个线程的优先级进行调度,决定他们的执行顺序。
多线程的优点:将主要进行io操作的线程(比如读取硬盘数据)的优先级调低,不会被io操作浪费大量的cpu时间
多线程的缺点:线程切换需要保存上下文,需要时间。
协程:用户态的轻量级的非抢占线程,协是协作的意思,即相互协作完成任务的协程们
// 伪代码
// 监听80端口,为每一个请求运行returnHtml(),即生成一个协程
function listener(){
// 监听80端口
returnHtml()
}
// go代表以协程的方式运行该函数
go function returnHtml(){
// 读取磁盘中的html文件
// 挂起自身对应的协程,让出线程给别的协程
// 读取完毕,返回html文件给用户
}
用户态:协程之间的切换是用户写的代码决定的。
轻量级:因为不存在线程的切换,而且某个协程的上下文
保存在该协程上,所以切换协程消耗很小。
非抢占:协程之间的切换不是通过优先级的抢占,而是用户决定的。
协程的缺点:只能在一个线程上运行,所以只能利用一个单核cpu。
协程解决了什么问题:
-
比线程切换耗时少
-
多线程存在的问题,多协程不存在,比如共享的资源。
问题:在使用协程的基础上,如何利用多核cpu?问题:在使用协程的基础上,如何利用多核cpu?
方案:多内核态线程+多协程
问题:由于协程的调用是用户写的代码决定的,
但是内核态线程是操作系统进行调度的。
所以这个方案本身还是要涉及共享资源的问题。
这无疑给用户写代码时,对调度的设计增加了难度。
但是对于大量网络io的应用程序,调度的复杂度却不高。
Golang的核心:GMP模型 --> www.zhihu.com/question/20…
接下来讲解两种GoLang能更有效利用cpu时间的情况:
若此时M0内核线程被操作系统中断,那么p便会移动到空闲的内核态线程,比如M1。
若此时M1的出于空闲状态,那么新的p调度器便会去偷别处p的G,然后挂载在空闲的M1上,这样cpu利用率更高。
最终目的:榨干cpu的计算时间,为此,不能把这时间浪费在io操作、线程切换以及空闲。