登录

  • 登录
  • 忘记密码?点击找回

注册

  • 获取手机验证码 60
  • 注册

找回密码

  • 获取手机验证码60
  • 找回
毕业论文网 > 外文翻译 > 计算机类 > 计算机科学与技术 > 正文

Node.js:使用JavaScript来构建高性能的网络程序外文翻译资料

 2022-10-26 10:10  

Node.js: Using JavaScript to Build High-Performance Network Programs

Stefan Tilkov bull; innoQ

Steve Vinoski bull; Verivue

Node.js — also called Node — is a server- side JavaScript environment (see http:// nodejs.org). Itrsquo;s based on Googlersquo;s runtime implementation — the aptly named “V8” engine. V8 and Node are mostly implemented in C and C , focusing on performance and low memory consumption. But, whereas V8 supports mainly JavaScript in the browser (most notably, Google Chrome), Node aims to support long-running server processes. Unlike in most other modern environments, a Node process doesnrsquo;t rely on multithreading to support concurrent execution of business logic; itrsquo;s based on an asynchronous I/O eventing model. Think of the Node server process as a single-threaded daemon that embeds the JavaScript engine to support customization. This is different from most eventing systems for other programming languages, which come in the form of libraries: Node supports the eventing model at the language level. JavaScript is an excellent fit for this approach because it supports event callbacks. For example, when a browser completely loads a document, a user clicks a button, or an Ajax request is fulfilled, an event triggers a callback. JavaScriptrsquo;s functional nature makes it extremely easy to create anonymous function objects that you can register as event handlers.

Multithreading versus Events

Application developers who deal with multiple I/O sources, such as networked servers handling multiple client connections, have long employed multithreaded programming techniques. Such techniques became popular because they let developers divide their applications into concurrent cooperating activities. This promised to not only make program logic easier to understand, implement, and maintain but also enable faster, more efficient execution. For applications such as Web servers performing significant amounts of I/O, multiple threads enable applications to better use available processors. Running multiple concurrent threads on a modern multicore system is straightforward, with each core simultaneously executing a different thread with true parallelism. On singlecore systems, the single processor executes one thread, switches to another and executes it, and so on. For example, the processor switches its execution context to another thread when the current thread performs an I/O operation, such as writing to a TCP socket. The switch occurs because completing that operation can take many processor cycles. Rather than wasting cycles waiting for the socket operation to finish, the processor sets the I/O operation in motion and executes another thread, thus keeping itself busy doing useful work. When the I/O operation ends, the processor again considers the original thread to be ready to execute because itrsquo;s no longer blocked while waiting for I/O. Even though many developers have successfully used multithreading in production applications, most agree that multithreaded programming is anything but easy. Itrsquo;s fraught with problems that can be difficult to isolate and correct, such as deadlock and failure to protect resources shared among threads. Developers also lose some degree of control when drawing on multithreading because the OS typically decides which thread executes and for how long. Event-driven programming offers a more efficient, scalable alternative that provides developers much more control over switching between application activities. In this model, the application relies on event notification facilities such asthe select() and poll() Unix system calls, the Linux epoll service, and the kqueue and kevent calls available in BSD Unix variants such as OS X. Applications register interest in certain events, such as data being ready to read on a particular socket. When the event occurs, the notification system notifies the application so that it can handle the event. Asynchronous I/O is important for event-driven programming because it prevents the application from getting blocked while waiting in an I/O operation. For example, if the application writes to a socket and fills the socketrsquo;s underlying buffer, ordinarily, the socket blocks the applicationrsquo;s writes until buffer space becomes available, thus preventing the application from doing any other useful work. But, if the socket is nonblocking, it instead returns an indication to the application that further writing isnrsquo;t currently possible, thereby informing the application that it should try again later. Assuming the application has registered interest with the event notification system in that socket, it can go do something else, knowing that it will receive an event when the socketrsquo;s write buffer has available space. Like multithreaded programming, event-driven programming with asynchronous I/O can be problematic. One problem is that not all interprocess-communication approaches can be tied into the event notification facilities we mentioned earlier. For example, on most OSs, for two applications to communicate through shared memory, sharedmemory segments provide no handles or file descriptors enabling the application to register for events. For such cases, developers must resort to alternatives such as writing to a pipe or some other event-capable mechanism together with writing to shared memory. Another significant problem is the sheer complexity of writingapplications in certain programming languages to deal with events and asynchronous I/O. This is because different events require different actions in different contexts. Programs typically employ callback functions to deal with events. In languages that lack anonymous functions and closures, such as C, developers must write individual functions specifically for each

剩余内容已隐藏,支付完成后下载完整资料


Node.js:使用JavaScript来构建高性能的网络程序

Stefan Tilkov bull; innoQ

Steve Vinoski bull; Verivue

Node.js也被称作Node, 是一个服务端JavaScript运行环境(参见http:// nodejs.org)。它是基于一个被称作V8引擎的谷歌开发的JavaScript 运行环境。V8和Node几乎都是用C或者C 来实现的,集中在高性能和低内存损耗上面。但是V8支持的JavaScript主要是在浏览器环境(最显然的谷歌Chrome浏览器),而Node旨在支持长时间运行的服务端进程。不同于绝大部分其他的现代环境,一个Node进程不依赖于多线程来支持并发运行的业务逻辑;它是基于一个异步的IO事件模型。我们可以认为Node服务器进程作为一个单线程进程,是一个嵌入JavaScript引擎来支持定制的守护进程。这不同于大多数其他编程语言,它们是通过库(函数库)来支持事件系统的;Node支持的事件模型是在语言层级的。JavaScript是非常适合这种方式的,因为它支持事件回调。例如,当浏览器完成加载一个文件、某个用户点击了一个按钮或者一个Ajax请求完成了,这些事件将触发一个回调。JavaScript的函数特性使得你极其容易创建一个匿名函数对象来注册你的事件处理。

多线程VS事件

需要处理多个IO源(例如:网络服务器处理多个客户端连接)的应用程序开发人员一直采用多线程编程技术。这种技术变得流行的原因是它允许开发人员将他们的应用程序分隔到多个并发合作的活动中。这个结果不仅使程序逻辑更容易理解、实现和维护,而且也能够更快、更高效的运行。

对需要执行大量的IO(操作)的应用程序(例如Web服务器)而言,多线程使得程序能够更好的利用可用的处理器。运行多个并发线程对现代的多核系统是直截了当的,每个核心同时执行不同的线程来完成真正的并发。对单核系统而言,单核处理器执行一个线程,切换到另一个线程执行,以此循环。例如,处理器在当前线程 执行IO操作(对一个TCP套接字进行写操作)时切换它的执行环境到另一个线程。这个切换发生因为完成这个操作需要多个处理器周期。而不是浪费时间循环等 待这个套接字操作完成,该处理器设置好IO操作后执行另一个线程,从而保持自己做一些有用的工作。当IO操作结束后,处理器再考虑让原来的线程变成等待执行状态因为它不再被IO等待而阻塞。

尽管许多开发人员在生产环境中已成功地使用了多线程,但大多数人认为,多线程编程绝非易事。它在独立性和正确性上充满了问题,例如在线程之间死锁和保护共享资源失效。开发人员在多线程上也失去了某种程度的控制,因为哪个线程执行和执行多久通常是操作系统决定的。

事件驱动的编程提供了一个更有效的,可扩展的替代,为开发人员提供更多的应用程序的活动之间的切换的控制。在这个模型中,应用程序依赖于事件通知设施,例如 Unix系统中的select()和poll()系统调用,Linux系统中的epoll服务,以及BSDUnix分支(如OSX)中的kqueue和 kevent调用。应用程序注册感兴趣的某些事件,如在指定的套接字上数据可以读取。当事件发生时,这个通知系统会通知应用程序,它可以处理事件了。

异步IO是重要的事件驱动编程,因为它可以防止应用程序在等待IO操作上被阻塞。例如,如果应用程序写入到一个套接字并填充套接字的底层的缓冲区,通常,套 接字阻止应用程序的写入,直到缓冲区空间变得可用,从而阻止了应用程序做任何其他有用的工作。但是,如果是非阻塞套接字,取而代之的是返回到应用程序,目 前无法进行写操作,从而通知应用程序,它应该稍后再试。假设应用程序在该套接字的事件通知系统已经注册了兴趣,可以去做些别的事情,可知它在收到一个事件 时,套接字的写缓冲区空间可用。

如同多线程编程,异步IO的事件驱动的编程也是有问题的。一个问题是,并非所有的进程间通信方法,可以换成我们前面提到的事件通知设施。例如,大多数操作系 统上,两个应用程序通过共享内存通信,共享内存段不提供句柄或文件描述符,使得无法注册的它们的事件。对于这样的情况下,开发人员必须采用向管道写的方式 或其他一些事件能力的机制,替换掉向共享内存写的方式。

另一个重要的问题是在某些编程语言编写的应用程序处理事件和异步IO的复杂性源于不同的事件,需要在不同环境下的执行不同行动。程序通常采用回调函数来处理 事件。在缺乏匿名函数和闭包的编程语言中,如C语言,开发人员必须编写特殊的函数,专门处理每个事件和事件的环境。确保这些函数都可以访问它们需要的数据 和环境信息,他们调用处理事件函数是令人费解的。许多这样的应用程序最终因为像意大利面条式缠绕的代码和全局变量而变得“坚不可摧”,难以维护。

“不是你爹”的JavaScript

无论你怎么看待作为一种编程语言的JavaScript,毫无置疑,它已经成为任何现代的基于HTML的应用程序的核心要素。服务端JavaScript是 一种合乎逻辑的下一步,使一个单一的编程语言使用在一个基于Web的分布式应用程序的全部方面。这种想法不是新的,例如,RhinoJavaScript 执行环境已经存在很长一段时间了。尽管如此,服务端的JavaScript不是一个主流的做法,直到最近才得到大规模普及。

我们相信,有一些因素导致了这种效果。被集体标记“HTML5”的一组技术的出现,降低了替代客户端平台的成本,实现需要去了解和利用JavaScript 来创建丰富的用户界面。NoSQL型数据库(如CouchDB和Riak)使用JavaScript来定义数据视图和过滤条件。其他动态语言,如Ruby 和Python等,已成为服务端开发可以接受的选择。最后,Mozilla和谷歌已经发布了的高性能的JavaScript运行环境是非常快速和可扩展性 的。

Node的编程模型

Node 的IO方式是严格的:异步的相互作用不是例外,他们是规则。全部IO操作通过高阶函数来处理,这是以函数作为参数的函数,这指明了什么时候需要做点事情的 时候去做什么。只在极少数情况下Node为开发人员提供了一个方便工作的同步函数,例如,删除或重命名文件。但是,一般情况,在可能需要网络或文件的IO 调用,控制权会立即返回给调用者。当发生一些感兴趣的事情,例如,数据变得可用于从网络套接字读取,输出流准备好写,或发生错误等等,适当的回调函数将被调用

图1 一个简单的HTTP文件服务器。输入或输出操作触发匿名函数。传入的请求触发服务器去解析目标URI,通过查找本地文件来匹配URI路径,如果发现匹配,则读取文件内容,写入相应的HTTP报头,作为响应,传给客户端。

图 1是一个实现从磁盘提供静态文件的HTTP Web服务器的简单的例子。即使对非Web开发人员,JavaScript的语法对事先接触到任何类似C语言的 人是相当友好的。更具体的话题之一是function(...)语法。这将创建一个匿名函数对象:JavaScript是一种函数性语言,因此,支持高阶 函数。一个开发人员在写或看Node程序的时候将随处见到这种写法。

该程序的主要流程是由显式调用的函数决定的。这些函数不会被任何的IO相关的事情阻塞,而是注册相应的处理程序回调。如果你在其他编程语言的事件库看到一个 类似的概念,你可能想知道这循环调用事件处理函数的阻塞调用隐藏在哪儿。这事件循环概念对Node而言是如此核心以至于它被隐藏在Node的实现中,这主 程序的目的是简单去建立合适的处理。这http.createServer函数是围绕一个低级别的高效的HTTP协议实现的封装,传递函数作为唯一的参 数。每当一个新的请求的数据准备好读时这个函数被调用。在另一个环境中,一个天真的实现(同步读取一个文件)能把它毁掉。Node不提供同步读取文件的机 会,唯一的选择是通过ReadFile函数注册可以读取数据时被调用的函数。

并发编程

一个Node服务器的进程,通常调用命令行使用类似“nodelt;文件名gt;”的方式运行单线程,但可以同时处理多个客户端。这似乎是一个矛盾,但 还记得这里有一个隐藏的主循环包围着代码,并且这实际处理在循环中只是一些数量的注册调用。没有实际的IO,更不用说业务逻辑处理,发生在循环体内。IO 相关的事件(如一个连接被建立或字节被发送或者被接受从一个套接字、文件或外部系统)触发其实际的处理。

图2 一个简单的流式HTTP文件服务器。从存储中读取文件块,然后通过HTTP块传输编码发送给客户端

图 2是一个简单的HTTP服务器稍微复杂的变体,它确实多了很多。在此基础上,它解析一个HTTP请求的URI和URI的路径映射到服务器上的文件名。但是 这次,该文件是一段一段的读取而不是一次读取所有数据。在某些情况下,以函数提供的情形下作为一个回调被调用。例如情形包括:当文件系统是准备好处理一定数目的字节时、当文件被读取完毕时或者当某种错误发生时。如果数据是可用的,它写入到HTTP输出流。Node的复杂的HTTP库支持的HTTP1.1的 块传输编码(chunked)。此外,从文件读取和写入到HTTP流都是异步的。

图 2中的示例显示了如何轻松地开发可以建立一个高性能,异步,事件驱动与适度的资源要求网络服务器。主要的原因是,JavaScript中,由于其函数性, 支持事件回调。事实上,这种模式被众所周知在任何客户端JavaScript开发中。此外,默认的异步IO强迫开发人员从一开始就采用异步模型。这是 Node与其他异步IO编程环境之间的主要区别之一,对其他编程环境而言,异步IO只是众多选择之一,通常被认为是过于先进的。

运行多个进程

在多个物理CPU或者多核环境下,并发执行不再是幻想而是实际。操作系统虽然可以在并发运行其他进程的同时,有效地安排其异步IO的Node的进程,但 Node的进程仍然运行在单线程模式下,因此其核心业务逻辑从来没有真正的并行过。这个问题在Node世界的解决方案是运行多个进程实例。

为了支持这一点,multi-node库(参见http://github.com/kris zyp/multi-node/)利用操作系统的进程间共享套接字的能力(并且它是用少于200行的Node的JavaScript代码实现的,现在 Node官方已经有Cluster模块支持该功能)。例如,你可以通过调用运行HTTP服务器,如在图1和图2并行调用multi-node的 listen()函数。这将启动多个进程,所有进程侦听相同的端口,有效地利用操作系统本身作为一个高效的负载均衡器。

服务端JavaScript的生态

Node 是一个较知名的框架和环境,支持服务器端JavaScript开发。社区已建立了一个完整的生态系统提供库或Node兼容。其中,如node-mysql 或node-couchdb等工具已经发挥出很重要的作用,支持异步交互的关系或NoSQL数据存储。许多框架提供了一个全功能的Web栈,例如 Connect和Express,这和Ruby世界的规范性产物Rack和Rails是相似的,他们是如此地流行。Node的包管理工具npm能安装各种 库和他们的依赖。最后,许多提供给客户端JavaScript的库被写入CommonJS模块也能在Node中工作。一个令人印象深刻的模块列表是 http://github.com/ ry/node/wiki/modules/。

鉴于此,在大多数Web开发项目,JavaScript作为一种先进的UI交互的知识是先决条件,选择使用一种编程语言完成一切变得相当诱人。Node.js的架构使得很容易地使用一个极富表现力的函数式语言来进行服务器编程,并且在不牺牲性能和编程主流风格下。

什么是Node.js?

Node.js是基于Chrome的V8引擎开发的一个软件平台,用于构建高效,可伸缩的网络程序,Node.js采用的事件驱动,非阻塞I / O模型,使它轻便,高效,并成为构建运行在分布式设备上的数据密集型实时应用的完美选择。 Node.js,最初由Ryan Dahl开发,还提供了一个REPL(交互式解释器)的环境用于交互式测试。

为什么要使用JavaScript包含的Node.js的?

bull;异步 - JavaScript是自然异步事件模型,非常适合通过回调构建高度可扩展的Web应用程序。

bull;更少的学习曲线 – 大量的已经熟悉JavaScript和异步编程多年的开发人员,正在进行浏览器端的JavaScript开发。

bull;快速的脚本引擎 – 引擎执行速度的巨大进步,使得实际应用中的JavaScript已经完全支持编写服务器端程序。

bull;代码共享 - 开发人员可以用一种语言编写整个web应用,这有助于减少开发客户端和服务器时所需要的语言切换,这样代码可以再客户端和服务器之间共享。

bull;代码转换 - JavaScript是一门编译目标语言,有许多开发语言是可以编译成javascrip。

bull;对NoSQL的支持 – JavaScript支持各种NoSQL数据库(例如CouchDB和 MongoDB),这些数据库的接口完美贴合javascript。

bull;JSON - 一个目前非常流行的数据交换格式,是JavaScript原生格式。

<strong

剩余内容已隐藏,支付完成后下载完整资料</strong


资料编号:[153997],资料为PDF文档或Word文档,PDF文档可免费转换为Word

您需要先支付 30元 才能查看全部内容!立即支付

企业微信

Copyright © 2010-2022 毕业论文网 站点地图