深入浅出NodeJS笔记(三)

第3章 异步I/O

阅读了这章内容后,最大的收获是更好地理解了阻塞/非阻塞I/O和Node中异步I/O的含义。

以前,谈到Node的异步I/O机制时,我就简单地理解为非阻塞I/O。实际上,这是不准确的。所谓I/O的阻塞与非阻塞,是操作系统对I/O操作的区分。执行阻塞I/O时,调用要等到所有相关的操作都结束时才算结束。这期间,CPU一直在等待I/O,不能处理其他任务,资源被浪费。执行非阻塞I/O时,调用直接返回,而不是等待I/O相关操作结束。这时,CPU可以处理其他的任务,不会浪费资源。然而,程序需要知道I/O操作何时结束,因此要不停地查询I/O的状态,此为轮询。轮询也会占用CPU资源,尽管有不同的轮询机制实现(如select,poll和epoll机制),优化了CPU资源利用,也只是减少了资源浪费。

注意,这里所说的非阻塞I/O的实现虽然可行,但只是操作系统级别的。对于应用程序来说,如果I/O操作的数据没有完全获取,就不能进行后续操作,因此仍然是一种同步。理想的状态是,应用程序发起一个I/O请求后,不需要执行轮询机制,也可以继续执行后续操作,只需在I/O结束时通过某种机制(消息或回调)将数据交给应用程序即可。这种场景下的I/O操作即使Node要实现的异步I/O

尽管系统不支持(或不能很好支持)异步I/O(因为需要轮询),但是可以通过阻塞I/O和线程池来模拟。使用一部分线程去执行I/O操作,再通过线程间通信机制,将结果传递给主线程。这样I/O操作是在其他线程执行的,并未阻塞主线程的执行,近似(线程需要调度)模拟了异步I/O的场景。Node采用了Windows平台下的IOCP模型实现异步I/O,*nix平台则通过自定义的线程池实现。我们平时所说Node是单线程,指的是Javascript的执行是单线程的,而I/O的操作的处理仍是利用底层系统提供的多线程机制。

接下来看Node异步I/O的具体实现原理。Node在进程启动时会创建一个循环,称为事件循环,每一次循环体执行成为一个tick。在每个tick中,检查是否有事件需要处理,如果有,检查是否有与事件关联的回调函数,如果有就执行它。如果没有事件处理,则退出。

如何判断是否有事件处理呢?Node采用了一系列观察者对象。事件循环通过询问观察者得知是否有事件处理。每个观察者维护者一个事件队列,当有磁盘I/O、网络请求发生时,事件对象被推入观察者队列,而事件循环则从这些队列中取出事件对象。这是一个典型的生产者-消费者模型。观察者对象根据事件的类型可以有多个,比如网络观察者,文件观察者等。另外,事件循环在查看各种观察者的队列时是有一定顺序的,如idle观察者(处理process.nextTick的回调,是非I/O异步调用)先于I/O观察者先于check观察者(处理setImmediate回调,也是非I/O异步调用)。

以Windows下的Node为例,在主程序发起一个I/O操作时,内建模块会通过libuv封装层发起系统调用,这时会创建一个请求对象。该对象封装了Javascript代码传入的参数,当前要执行的函数以及回调函数的信息。然后这个请求对象被推送到线程池等待执行。此时,Javascript主程序调用立即返回,执行后续代码。这时异步I/O的第一个阶段。接下来,当线程池中I/O操作结束后,仍然将结果写入请求对象中,并通知IOCP执行完毕,归还线程。事件循环在每个tick中会询问I/O观察者,后者调用IOCP的API查询是否有执行完的请求,如果有,就将相应的请求对象压入I/O观察者的队列。事件循环得到请求对象后,执行其中的回掉函数。这时异步I/O的第二个阶段。

由Node采用了单线程模型,不会有多线程上下文切换开销较大的问题,这时Node高性能的一个原因。事实上,虽然每个到达的请求都未阻塞后续请求,但请求的处理依然以队列的顺序进行处理,只不过每个请求的处理也不会阻塞。具体处理的过程依然依赖于底层的线程池的性能。

### 回答1: Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,通过它可以使用JavaScript开发服务器端应用程序。Node.js的设计初衷是解决传统的后端开发中瓶颈问题,如高并发、I/O密集以及复杂的数据处理等。 Node.js拥有非阻塞式I/O与事件驱动的特点,这使得在处理大量并发连接时表现出色。与传统的多线程服务器相比,Node.js的单线程事件循环机制能够更高效地利用CPU和内存资源,并且能够处理更多的并发请求。 通过使用Node.js,开发者可以使用JavaScript语言进行全栈式开发,避免了前后端技术栈的差异性,提高了开发效率。Node.js的模块化机制使得使用第方模块更加方便和灵活,有助于代码的复用和维护。 在图灵中,我们可以通过学习Node.js来掌握以下几个核心概念: 1. 事件驱动与异步编程:Node.js利用事件循环机制实现异步非阻塞I/O,通过回调函数实现事件的处理。理解事件驱动的编程思维,能够使开发者更好地处理高并发情况下的请求。 2. HTTP服务器与路由:Node.js提供了HTTP模块,可以搭建自己的Web服务器,并实现路由功能。学习如何创建HTTP服务器和处理请求,能够让我们更好地理解Web开发的原理。 3. NPM与模块化开发:NPM是Node.js的包管理工具,可以方便地安装和管理第方模块。学习NPM的使用,了解模块化开发的概念和实践,能够更好地管理项目的依赖和提高代码复用性。 4. 文件系统与流操作:Node.js可以轻松地进行文件的读写和操作,通过流的方式进行数据的传输和处理,提高了大数据量的处理效率。 5. Express框架与数据库操作:Express是Node.js的Web应用程序框架,可以简化Web开发的过程。同时,Node.js也支持各种数据库的操作,学习如何使用Express框架和操作数据库,能够更好地构建实际的应用程序。 通过深入浅出地学习Node.js,我们可以全面掌握JavaScript在服务器端的应用,提升自己的全栈开发能力,能够更好地应对日益复杂的网络开发需求。 ### 回答2: 深入浅出node.js图灵是指以易于理解和掌握的方式介绍node.js这个开发平台。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它主要用于服务器端编程,可以构建高性能的网络应用。 深入浅出的意思是通过简单明了的解释和示例来讲解node.js的关键概念和用法,使初学者能够迅速上手。在深入方面,不仅仅是讲解语法和API,还涉及到node.js的设计原理和性能优化等方面的知识。在浅出方面,避免过多的技术术语和复杂的概念,注重引导读者理解核心的思想和模式。 在node.js图灵的学习中,可能会包含以下内容: 1. Node.js的安装和配置:介绍如何下载、安装和配置Node.js的运行环境。 2. JavaScript快速回顾:回顾JavaScript的基本语法和用法,为后续的Node.js开发做准备。 3. 模块和包管理:讲解Node.js的模块系统和npm包管理器,了解如何使用、创建和发布模块和包。 4. 异步编程:深入理解Node.js的事件驱动和非阻塞I/O模型,学习如何编写异步代码以提高系统的性能和可伸缩性。 5. HTTP和网络编程:探索Node.js在网络编程中的应用,如创建HTTP服务器、发送和接收HTTP请求等。 6. 数据库和存储:介绍如何使用Node.js操作数据库,如MySQL、MongoDB等,以及文件系统的读写操作。 7. Web框架和中间件:学习常用的Node.js Web框架,如Express.js,以及如何使用中间件来处理请求和响应。 8. 调试和优化:掌握Node.js的调试技巧和性能优化策略,以提高应用的稳定性和效率。 通过深入浅出node.js图灵的学习,可以快速掌握Node.js的基本概念和用法,并能够使用Node.js构建高性能的网络应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值