各种语言的并发原理整理

NodeJs严格来说不是一门语言而是一个运行于服务端的JavaScript解释器。Node.js是一个基ChromeV8引擎的JavaScript运行环境,一个让JavaScript运行在服务端的开发平台,实质是对Chrome V8引擎进行了封装。V8 JavaScript引擎是由Google公司使用C++语言开发的一种高性能JavaScript引擎,该引擎并不局限于在浏览器中运行。类似我们在使用PHP和Python时需要安装的运行环境一样的道理。

Node 使用事件驱动 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。在Java、PHP或者.NET等服务器语言中,会为每一个客户端连接创建一个新的线程,而每个线程需要耗费大约2MB内存,也就是说,理论上一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让web应用程序支持更多的用户,就需要增加服务器的数量,而web应用程序的硬件成本当然就上升了。

NodeJs不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了就触发一个内部事件,通过非阻塞I/O事件驱动机制让Node.js程序宏观上也是并行的。使用Node.js一个8GB内存的服务器,可以同时处理超过4万用户的连接。

PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源的、简单的、面向对象的、解释型的、健壮的、安全的、性能非常之高的、独立于架构的、可移植的、动态的脚本语言。PHP语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。php的解释器是zend,zend是用c语言写的,zend将PHP翻译成c语言,然后再编译成机器码,这时候机器才能执行。这就是php的底层是c的由来。

Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。Python和PHP类似也有自己的解释器,常见的解释器是C语言编辑的,所以也称CPython,还有Python自己实现的解释器pypy。Python社区的标准是CPython实现,是C语言写的。

协程

在操作系统当中有两种概念,一个是进程,一个是线程。进程拥有独立的资源空间,也就是各个进程之间不共享资源,操作系统为了能够让多个进程“同时”运行,采用了时间片轮换机制,CPU某一时刻属于一个进程,下一时刻就切换到另外一个进程,当时间片足够短的时候,我们就可以感觉到多个进程同时运行。

因为进程之间不共享资源,切换的代价就会比较的高,所以后来就设计了线程。一个进程可以含有多个线程,各个线程共享一个进程中的资源,线程的切换只是切换CPU中的执行代码,运行时所需要的资源几乎可以不用切换,大大提高了切换效率。

其实线程也有自己独立的资源,比如运行时创建的堆栈信息等,一般线程初始化的时候会预分配1M左右的空间用于存放这些资源,所以切换依然是有成本的。

目前比较流行的一种更加高效的方式是协程,协程是以多占用内存为代价,实现多任务的并行的,协程有多线程版本的也有单线程版本的

以Nodejs为例来说(js是单线程的),nodjes中的协程其实是多个可以并行执行的函数的协作。怎么来理解这句话呢?传统的程序执行采用堆栈式的执行方式,只有当调用的子函数完全执行完毕才会结束执行父函数,执行信息保存在一个堆栈当中。 协程其实是突破了堆栈数的限制,主函数一个堆栈,每个异步的回调也有自己的堆栈,当程序执行发生异步的时候,执行权限可以切换给其他函数,因为堆栈信息一直保留在运行环境中(没有被切换出去),所以切换成本非常小,一般是直接修改执行函数的引用就可以完成切换。

Nodejs Promise.all执行async函数就是运行一段协程代码,await关键字就是切换协程,在await后就去执行其他协程的代码了。es6中为了实现协程,提供了Generator函数和yield关键字,但是语法比较繁琐,后来对其进行了包装,变成了async函数和await关键字

nodejs协程的缺点 线程是基于时间片的,也就是说一个线程卡死,不会影响其他线程的执行,但是nodejs协程不同,一个协程卡死将导致执行权限无法释放,导致其他的协程也无法执行。

go语言的协程

nodejs因为是单线程的,协程无法使用多核,也就是说无法真正的并发执行多个函数。 go语言设计了多核版本的协程,也就是说,同一时间多个协程可以被多个CPU真正的并发执行,或者你可以开多个线程,让多个线程去调度协程序,避免程序假死的问题。因为go的优秀的协程处理机制,区块链优先采用了go作为开发语言。

不同于传统的多进程或多线程,golang的并发执行单元是一种称为goroutine的协程。语言级别支持协程(goroutine)并发(协程又称微线程,比线程更轻量、开销更小,性能更高),操作起来非常简单,语言级别提供关键字(go)用于启动协程,并且在同一台机器上可以启动成千上万个协程。协程经常被理解为轻量级线程,一个线程可以包含多个协程,共享堆不共享栈。协程间一般由应用程序显式实现调度,上下文切换无需下到内核层,高效不少。协程间一般不做同步通讯,而golang中实现协程间通讯有两种:1)共享内存型,即使用全局变量+mutex锁来实现数据共享;2)消息传递型,即使用一种独有的channel机制进行异步通讯。

Python协程 asyncio.create_task() 函数用来并发运行作为 asyncio 任务 的多个协程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章