关于协程:nodejs和golang协程的不同
nodejs和golang都是支持协程的,从表现上来看,nodejs对于协程的支持在于async/await,golang对协程的支持在于goroutine。关于协程的话题,简单来说,可以看作是非抢占式的轻量级线程。
协程本身
一句话概括,上面提到了
"可以看作是非抢占式的轻量级线程"。
在多线程中,把一段代码放在一个线程中执行,cpu会自动将代码分成碎片,并在一定时间切换cpu控制权,线程通过锁机制确保自己使用的资源在cpu执行别的线程的代码时被修改(占用的内存堆栈、硬盘数据资源等),也就是说通过锁机制,
线程a在一块内存中创建了一个变量,线程a代码还没结束,cpu切换去执行线程b了,但是由于锁,线程b无法使用这块内存。
如果仅在单核单线程cpu下来看,多线程和多协程没有任何区别,因为线程不能并行,只能是cpu分碎片执行。
协程就是类似这个意思。协程是线程内的东西(暂且不谈多线程下的协程),当协程遇到阻塞时,就切换线程控制权,让线程去执行另外一个协程,只不过这个过程是排队的。这和nodejs的事件轮询是一回事,在nodejs中先告知系统我现在要
读取文件了,系统读取,io阻塞了,nodejs去执行下一段代码B,执行完后检查阻塞是否等待完毕,如果等待完毕就把结果推到事件队列背后去执行回调函数。这一段话我用协程的意思来表达一下,把读取文件,读取结束后执行相应操作放在一个协程a
内,执行代码B放在一个协程b内,线程执行协程a,a遇到io阻塞了,切换线程控制权,执行协程b,b执行结束,切换线程控制权,执行协程a。对于js用户来说,协程是回调的另一种表现形式。
function sleep(ms){
return new Promise((resolve,reject)=>setTimeout(
()=>resolve(),ms
))
}
(async function (){
await sleep(3000)
console.log("你好")
}())
(async function (){
await sleep(3000)
console.log("世界")
}())
可以这么看,执行async函数就是运行一段协程代码,await关键字就是切换协程,在await后就去执行其他协程的代码了。
func deferPrint(str string){
time.Sleep(time.Second*2)
fmt.Println(str)
}
func main(){
go deferPrint("你好")
go deferPrint("世界")
//如果主协程不阻塞,永远不会切换
time.Sleep(time.Seconds*2)
}
golang的go关键字就是将一段代码放在一个协程里,线程选择协程运行,碰见阻塞就自动切换协程运行,但需要注意的是,golang不会因为一个协程运行结束就自动切换,必须是阻塞之后
核心区别
锁机制
golang的协程是可以带锁的 Lock.Mutex() Unlock(),nodejs是号称永远不会死锁也根本没有锁这回事。
没有锁会导致的问题在于占用的资源被轻易修改
比如读取一个文件,如果该文件为0kb我就写一个字符串进去,如果大于0kb,我就不执行任何操作。协程中会有两次阻塞,第一次是读取该文件,判断文件大小,第二次是写入。假如有两个函数签名如下
async function getFileSize(filename) : number
async function writeFile(data,filename) :bool
async function exec(){
size = await getFileSize("./test.txt");
if(size==0){
await writeFile("你好","./test.txt")
console.log("ok!")
}
}
如果我第一次判断结束后另一个协程里执行了插入操作,那么几个函数的执行顺序就会变成
A: getFileSize()检查文件大小,协程阻塞,切换协程
B: 写入文件,协程阻塞,切换协程
A: getFileSize()检查文本大小结束,可以插入,执行writeFile()
但是此时队列中还有一个B协程的插入操作会在A之前执行,A协程对此不知道,以为文件还是0kb
如果文件被上锁了
A: getFileSize()检查文件大小,协程阻塞,切换协程
B: 写入文件,哦——协程A锁住了这个文件,那我等他释放把,切换协程
A: getFileSize()完成,插入操作
B: 哦——协程A还在占用,那我接着等
A: 搞定了,释放锁,我已经没有什么要执行的了,把我从队列里删掉吧
B: 协程A释放了文件的锁,现在我可以写入了
线程支持
golang之所以要支持锁协程,我想是为了多线程支持。golang中可以启用多个线程并行执行相同数量的协程。
nodejs受限于v8的isolate机制,只能跑在单线程中。所有代码无法并行执行,无法处理计算密集型应用场景。
切换机制
nodejs使用await阻塞协程,手动切换线程控制权,node的协程是c++控制的,c++里写了这个函数可以被推入事件队列就能够用promise封装成协程
golang在协程阻塞时自动切换协程,所以在写golang的时候所有的代码可以都写同步代码,然后用go关键字去调用,golang的协程是自己规定的,所有
函数在阻塞时都必须切换线程控制权
取返回值
nodejs中async函数是能直接返回值的
golang只能传递一个引用的channel
总的来说golang和nodejs应用场景不同。nodejs适合前端鼓捣,用plug/ejs配合express/koa2从服务器http请求数据后再填到模版引擎里
golang类似与小c++,最大的亮点就是使用协程管理多线程
对语言来说,不应该选边站,但还是捧一波c#,除了只能在.net上运行其他碾压其他所有对手
关于协程:nodejs和golang协程的不同的更多相关文章
- 面试必问:Golang高阶-Golang协程实现原理
引言 实现并发编程有进程,线程,IO多路复用的方式.(并发和并行我们这里不区分,如果CPU是多核的,可能在多个核同时进行,我们叫并行,如果是单核,需要排队切换,我们叫并发) 进程和线程的区别 进程是计 ...
- golang协程——通道channel阻塞
新的一年开始了,不管今天以前发生了什么,向前看,就够了. 说到channel,就一定要说一说线程了.任何实际项目,无论大小,并发是必然存在的.并发的存在,就涉及到线程通信.在当下的开发语言中,线程通讯 ...
- golang协程同步的几种方法
目录 golang协程同步的几种方法 协程概念简要理解 为什么要做同步 协程的几种同步方法 Mutex channel WaitGroup golang协程同步的几种方法 本文简要介绍下go中协程的几 ...
- Python与Golang协程异同
背景知识 这里先给出一些常用的知识点简要说明,以便理解后面的文章内容. 进程的定义: 进程,是计算机中已运行程序的实体.程序本身只是指令.数据及其组织形式的描述,进程才是程序的真正运行实例. 线程的定 ...
- Golang协程实现流量统计系统(3)
进程.线程.协程 - 进程:太重 - 线程:上下文切换开销太大 - 协程:轻量级的线程,简洁的并发模式 Golang协程:goroutine Hello world package main impo ...
- Golang协程池(workpool)实现
背景 因与工作相关,所以本文中的数据都进行了更改,但逻辑是一样的. 笔者的服务ServerA会请求服务ServerH获取一些数据,但ServerH的接口有个N秒内只能请求M次的限制,并返回false. ...
- 011-Python-进程、线程于协程
1.进程与线程 进程: 一个程序要运行时所需的所有资源的集合: 一个进程至少需要一个线程,这个线程称为主线程,一个进程里可以包含多个线程: cpu 核数越多,代表着你可以真正并发的线程越多2个进程之间 ...
- {python之协程}一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二
python之协程 阅读目录 一 引子 二 协程介绍 三 Greenlet 四 Gevent介绍 五 Gevent之同步与异步 六 Gevent之应用举例一 七 Gevent之应用举例二 一 引子 本 ...
- go语言之进阶篇主协程先退出导致子协程没来得及调用
1.主协程先退出导致子协程没来得及调用 示例: package main import ( "fmt" "time" ) //主协程退出了,其它子协程也要跟着退 ...
随机推荐
- iOS 开发之 - 关闭键盘 退出键盘 的5种方式
iOS 开发之 - 关闭键盘 退出键盘 的5种方式 1.点击编辑区以外的地方(UIView) 2.点击编辑区域以外的地方(UIControl) 3.使用制作收起键盘的按钮 4.使用判断输入字元 5 ...
- intellij IDEA 更新java后不用重启tomcat
最近项目大了,每次修改后重启都要等和很久,那个煎熬…… 为了解决这个问题,万能的Google 装了这个 JREBEL 5.63最新的 安装步骤: 一.IDEA在线搜索 jrebel 安装 二.破 ...
- cat /proc/cpuinfo | awk -F: '/name/{print $2}' | uniq -c
cat /proc/cpuinfo | awk -F: '/name/{print $2}' | uniq -c
- vue、react、angular三大框架对比
前端的三大框架当属vue.react以及angular了,个人比较偏向react,它的社区比较繁荣,有很多丰富的组件 .angular的话感觉编译时间有点长,等待很恼火. vue与react vue和 ...
- 对于iOS 7 隐藏特性和解决之道
当 iOS7 刚发布的时候,全世界的苹果开发人员都立马尝试着去编译他们的app,接着再花上数月的时间来修复任何出现的故障,甚至重做app.这样的结果,使得人们根本无暇去探究 iOS7 所带来的新东西. ...
- ES6 中的let 声明变量
1.let是声明的是块级变量,不会污染全局,一般条件与循环中会用到: 2.let 不可以变量提升: 3.let不遵循作用域,一个作用域内如果有该变量,就不会到全局去找,也不可以在一个作用域重复声明一 ...
- bfs 邻接表
#include<stdio.h> #include<stdlib.h> #include<string.h> struct node { int date; st ...
- Java 远程调用之Hessian简例
1. [代码]1.服务接口(Hello.java) package server; public interface Hello { String hello(String name);}2. [代码 ...
- codeforces 440B. Balancer 解题报告
题目链接:http://codeforces.com/problemset/problem/440/B 题目意思:给出 n 个数,求出这 n 个数的平均值avg,问对于这 n 个数里面中的每一个数,要 ...
- 并不对劲的bzoj4804:欧拉心算
题目大意 \(t\)(\(t\leq5000\))组询问,每次询问给出\(n\)(\(n\leq10^7\)),求: \[\sum_{i=1}^{n}\sum_{j=1}^{n}\phi(gcd(i, ...