设为首页 收藏本站
查看: 1072|回复: 0

[经验分享] 关于协程:nodejs和golang协程的不同

[复制链接]

尚未签到

发表于 2018-9-20 09:30:00 | 显示全部楼层 |阅读模式
  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(){

  >  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上运行其他碾压其他所有对手


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-598663-1-1.html 上篇帖子: golang csv,xls,xlsx 下篇帖子: Golang学习 - 学习资源列表
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表