当前位置: 首页 > 后端技术 > Node.js

JavaScript单线程并不简单,md

时间:2023-04-03 15:00:24 Node.js

我们经常听说JavaScript是单线程的,那么这个单线程是什么意思呢?单线程是否意味着JavaScript存在性能缺陷?在浏览器端,JavaScript单线程是指JavaScript执行线程和UI渲染线程共享同一个线程。对于NodeJS来说,单线程是指它的JavaScript执行线程是单线程的。虽然JavaScript只能在单线程中执行,但JavaScript引擎却不能。它可以创建多个线程来服务于主线程。WebWorker已经被大部分浏览器支持,NodeJS也有自己的线程池来处理I/O操作。无论前端还是后端,JavaScript已经可以使用多线程来提高程序性能。NodeJS单线程异步I/O模型NodeJS是一种单线程异步I/O模型。也就是说,NodeJS代码执行占用一个线程,而代码中的I/O操作则交给其他线程执行,执行完毕后将结果返回给主线程。对于NodeJS来说,单线程不仅不是劣势,对于降低编程复杂度也有着重要的作用。单线程避免了多线程编程模型中的多线程死锁和状态同步等问题。异步I/O避免了单线程同步编程模型的阻塞问题,使CPU得到更充分的利用。NodeJS异步I/O模型的实现离不开libuv层。libuv提供了一个线程池来执行I/O操作,执行完成后将结果返回给执行线程,因此I/O操作不会阻塞执行线程继续执行。libuv是一个事件驱动的异步I/O库。它是跨平台的。*nix平台下,线程池是自己实现的。在windows平台上,采用IOCP。IOCP还是基于线程池的原理。libuv的线程池默认为4个线程。接下来我们看一下Linux环境下NodeJS的多线程。查看NodeJS多线程首先,我们需要先写一个js脚本,写一个定时器,这样脚本执行完就不会关闭。setInterval(function(){},1000)node命令执行脚本,打开另一个窗口(或者后台执行程序)查看NodeJS进程下的线程状态。$ps-aPIDTTYTIMECMD16699pts/200:00:00node16706pts/000:00:00ps$ps-L-p16699PIDLWPTTYTIMECMD1669916699pts/200:00:00node1669916700pts/200:00:00V8WorkerThread1669916701点/200:00:00V8WorkerThread1669916702点/200:00:00V8WorkerThread1669916703点/200:00:00V8WorkerThread1669916700:0节点可以/2看到包括V8引擎的工作线程在内,已经开启了6个线程(MACOS系统使用ps-M-p命令)。目前还没有创建线程池,只有在进行I/O操作后才会创建线程池。在脚本中添加异步读取文件的代码,激活线程池。require('fs').readFile('test.js',function(){})setInterval(function(){},1000)重启脚本,可以看到新启动的4个线程正是libuv线程池默认值为4个线程。$ps-aPIDTTYTIMECMD16745pts/200:00:00node16755pts/000:00:00ps$ps-L-p16745PIDLWPTTYTIMECMD1674516745pts/200:00:00node1674516746pts/200:00:00V8WorkerThread1674516747点/200:00:00V8WorkerThread1674516748点/200:00:00V8WorkerThread1674516749点/200:00:00V8WorkerThread167451670015点/265pts/200:00:00node1674516752pts/200:00:00node1674516753pts/200:00:00node1674516754pts/200:00:00node可以修改环境变量process.env.UV_THREADPOOL_SIZE(最多128个)使NodeJS能够支持更多线程。//jsprocess.env.UV_THREADPOOL_SIZE=64require('fs').readFile('test.js',function(){})setInterval(function(){},1000)//bash$ps-aPIDTTYTIMECMD16782pts/200:00:00node16852pts/000:00:00ps$ps-L-p16782|wc-l71重新执行脚本,可以看到减去第一行和6个初始线程,有64个线程在为NodeJS异步I/O服务。高并发高可用JavaScript是单线程的,但是JavaScript引擎可以创建多个线程为主线程服务,而NodeJS的主线程就像一个调度器,可以将网络请求等I/O操作分发给other线程进行处理,结果通过事件机制返回给主线程。所以用NodeJS写的服务器可以支持海量的并发,这也是NodeJS的优势。NodeJS主线程不应该做大量的计算,因为它会阻塞主线程。所以总的来说,NodeJS适合I/O密集型场景,不适合CPU密集型场景。除了多线程支持,NodeJS还提供了child_process和cluster接口,允许用户创建许多子进程来处理任务。单线程NodeJS应用程序是脆弱的,但组的力量是强大的。多进程多线程的NodeJS是服务器性能和稳定性的保证。参考http://docs.libuv.org/en/latest/threadpool.html《深入浅出 NodeJS》https://nodejs.org/dist/latest-v8.x/docs/api/child_process.htmlhttps://nodejs。org/dist/latest-v8.x/docs/api/cluster.html