Node.js:利用JavaScript构建高性能网络应用
关键词:Node.js,JavaScript,多线程,节点编程
尽管多线程编程已经得到普及,但其难度让很多开发者头疼,事件驱动编程提供了一种更高效、可扩展的替代方案,为实现高效的编程,JavaScript成为了首选。这篇文章为我们介绍了用JavaScript开发的支持服务器端的框架和环境——Node.js,并介绍了其运行原理。
多线程与事件
处理多个输入/输出源的应用程序开发人员,例如处理多个客户端连接的网络服务器,长期以来一直采用多线程编程技术。这种技术变得流行是因为它们让开发人员将他们的应用程序分成并发的协作活动。这不仅使程序逻辑更容易理解、实现和维护,还能实现更快、更高效的执行。
对于执行大量输入/输出的应用程序(如网络服务器),多线程使应用程序能够更好地使用可用的处理器。在现代多核系统上运行多个并发线程非常简单,每个内核以真正的并行性同时执行不同的线程。在单核系统中,单个处理器执行一个线程,切换到另一个线程并执行它,等等。例如,当当前线程执行输入/输出操作(如写入TCP套接字)时,处理器将其执行上下文切换到另一个线程。发生切换是因为完成该操作可能需要许多处理器周期。处理器不是浪费周期等待套接字操作完成,而是启动输入/输出操作并执行另一个线程,从而让自己忙于做有用的工作。当输入/输出操作结束时,处理器再次认为原始线程准备好执行,因为它在等待输入/输出时不再被阻塞。
尽管许多开发人员已经成功地在生产应用程序中使用了多线程,但大多数人都认为多线程编程一点也不容易。它充满了难以隔离和纠正的问题,例如死锁和无法保护线程间共享的资源。开发人员在绘制多线程时也会失去一定程度的控制,因为操作系统通常会决定哪个线程执行以及执行多长时间。事件驱动编程提供了一种更高效、可扩展的替代方案,为开发人员提供了对应用程序活动之间切换的更多控制。在这个模型中,应用程序依赖于事件通知工具,例如在BSD Unix变体(如OSX)中可用的select()和poll()Unix系统调用、Linux epoll服务以及kqueue和kevent调用。应用程序注册对某些事件的兴趣,例如准备在特定套接字上读取的数据。当事件发生时,通知系统通知应用程序,以便它可以处理该事件。
异步输入/输出对于事件驱动编程很重要,因为它可以防止应用程序在等待输入/输出操作时被阻塞。例如,如果应用程序写入套接字并填充套接字的底层缓冲区,通常,套接字会阻止应用程序的写入,直到缓冲区空间变得可用,从而阻止应用程序执行任何其他有用的工作。但是,如果套接字是非阻塞的,它会向应用程序返回一个指示,表明当前不可能进一步写入,从而通知应用程序它应该稍后再试。假设应用程序已经向该套接字中的事件通知系统注册了兴趣,它可以去做别的事情,知道当套接字的写缓冲区有可用空间时,它将接收一个事件。
像多线程编程一样,使用异步输入/输出的事件驱动编程可能会有问题。一个问题是,并非所有的进程间通信方法都可以绑定到我们前面提到的事件通知工具中。例如,在大多数操作系统上,两个应用程序通过共享内存进行通信,共享内存段不提供句柄或文件描述符,使应用程序能够注册事件。对于这种情况,开发人员必须求助于替代方法,例如写入管道或其他一些支持事件的机制,以及写入共享内存。
另一个重要的问题是用某些编程语言编写应用程序来处理事件和异步输入/输出的复杂性。这是因为不同的事件在不同的上下文中需要不同的操作。程序通常使用回调函数来处理事件。在缺乏匿名函数和闭包的语言中,比如C语言,开发人员必须为每个事件和事件上下文专门编写单独的函数。当这些函数被调用来处理事件时,确保它们都能够访问它们所需的数据和上下文信息是非常令人费解的。许多这样的应用程序最后只不过是密不透风、难以维护的意大利面条代码和全局变量的缠结。
不是“老牌”的JavaScript
无论你如何看待JavaScript作为一种编程语言,毫无疑问,它已经成为任何现代基于HTML的应用程序的核心元素。服务器端的JavaScript是一个合乎逻辑的下一步,使得基于Web的分布式应用程序的所有方面都可以使用单一的编程语言。这个想法并不新鲜——例如,Rhino JavaScript执行环境已经存在很长时间了。尽管如此,服务器端的JavaScript还不是一种主流方法,只是最近才获得了巨大的普及。
我们认为,许多因素导致了这种影响。统称为“HTML5”的一系列技术的出现降低了替代客户端平台的吸引力,迫使人们需要了解和利用JavaScript来创建丰富的用户界面。像CouchDB和Riak这样的NoSQLtype数据库使用JavaScript来定义数据视图和过滤标准。其他动态语言,如Ruby和Python,已经成为服务器端开发可以接受的选择。最后,Mozilla和谷歌都发布了高性能的JavaScript运行时实现,速度极快且可扩展。
节点编程模型
节点的输入/输出方法是严格的:异步交互不是例外;他们是规则。每一个输入/输出操作都是通过高阶函数来处理的——也就是说,函数将函数作为参数——这些函数指定当有事情要做时该做什么。只有在极少数情况下,Node的开发人员才添加了一个同步工作的便利功能——例如,删除或重命名文件。但是,一般来说,当调用可能需要网络或文件输入/输出的操作时,控制权会立即返回给调用者。当一些有趣的事情发生时,例如,如果数据可以从网络套接字读取,输出流准备好写入,或者发生错误,就会调用适当的回调函数。
图1是一个实现HTTP Web服务器的简单例子,该服务器从磁盘提供静态文件。即使对非网络开发人员来说,JavaScript的语法对于那些之前接触过类似C语言的人来说也应该是相当明显的。更具体的主题之一是函数(...)语法。这创建了一个未命名的函数:JavaScript是一种函数式语言,因此支持更高阶的函数。编写或查看Node程序的开发人员会在任何地方看到这些。
我会到处看到这些。程序的主要流程由显式调用的函数决定。这些函数从不阻塞任何与输入/输出相关的东西,而是注册适当的处理程序回调。如果您在其他编程语言的事件库中看到过类似的概念,您可能会想调用事件循环的显式阻塞调用隐藏在哪里。事件循环概念是节点行为的核心,它隐藏在实现中;主程序的目的只是设置适当的处理程序。http。createServer函数是一个低级高效HTTP协议实现的包装器,作为唯一的参数传递给一个函数。每当准备好读取新请求的数据时,就会调用该函数。在另一个环境中,天真的实现可能会通过同步读取文件并将其发送回来而破坏事件的效果。节点不提供同步读取文件的机会,唯一的选择是通过readFile注册另一个函数,只要可以读取数据,readFile就会被调用。
并发编程
通常使用类似“node”的命令从命令行调用的节点服务器进程运行singlethreaded,但可以同时为许多客户端提供服务。这似乎是一个矛盾,但是回想一下,在代码周围有一个隐式的主循环,在那个循环中实际发生的只是一些注册调用。在循环体中没有实际的输入/输出,更不用说业务逻辑处理了。与输入/输出相关的事件触发实际的处理,例如建立连接或从套接字、文件或外部系统发送或接收字节。
图2是简单的HTTP服务器的一个稍微复杂的变体,但是它做得更多。同样,它从一个HTTP请求中解析URI,并将URI的路径组件映射到服务器上的一个文件名。但这一次,文件是以更小的块读取的,而不是一次全部读取。在某些情况下,调用为场景提供的回调函数。示例情况包括:当文件系统层准备向应用程序传递大量字节时,当文件被完全读取时,或者当发生某种错误时。如果数据可用,它将被写入HTTP输出流。节点复杂的HTTP库支持HTTP1.1的分块传输编码。同样,读取文件和写入HTTP流都是异步进行的。
图2中的例子展示了开发人员如何轻松地构建一个高性能、异步、事件驱动的网络服务器,并且对资源要求不高。主要原因是JavaScript由于其功能性,支持事件回调。事实上,这种模式对于任何客户端JavaScript开发人员来说都是众所周知的。此外,将异步I/O设为默认会迫使开发人员从一开始就采用异步模型。这是Node和在其他编程环境中使用异步I/O的主要区别之一,在其他编程环境中,这只是众多选项之一,通常被认为过于高级。
运行多个进程
在有多个物理CPU或内核可用的硬件环境中,并行执行不是幻想,而是现实。尽管操作系统可以高效地调度节点进程,使其异步输入/输出交互与系统上运行的其他进程并行,但节点仍然在单个进程中运行,因此永远不会并行执行其核心业务逻辑。在节点世界中,这个问题的常见解决方案是运行多个流程实例。
为了支持这一点,多节点库(参见http://github.com/kriszyp/多节点)利用了操作系统在进程之间共享套接字的能力(在不到200行的Node Java Script中实现)。例如,您可以通过调用多节点的listen()函数并行运行如图1和2所示的HTTP服务器。
服务器端的JavaScript生态系统
Node是支持服务器端JavaScript开发的著名框架和环境之一。该社区已经为Node创建了一个完整的库生态系统,或者与Node兼容。其中,node-mysql或nodecouchdb等工具通过分别支持与关系和NoSQL数据存储的异步交互发挥了重要作用。许多框架提供了功能齐全的Web栈,例如Connect和Express,它们在范围上可以与Ruby世界中的Rack和Rails相媲美,如果不是的话(还没有?)的受欢迎程度。节点包管理器npm支持库及其依赖项的安装。最后,许多可用于客户端JavaScript的库都是按照CommonJS模块系统编写的,它们也可以与Node一起工作。http://github.com/里/节点/维基/模块提供了一份令人印象深刻的节点模块列表。
外文原文资料信息
[1]外文原文作者:Stefan Tilkov、Steve Vinoski
[2] 外文原文所在书名或论文题目:Node.js: Using JavaScript to Build High-Performance Network Programs
[3] 外文原文来源: The Functional Web.NOVEMBER/DECEMBER 2010,80-83.
二、外文原文资料:
Node.js: Using JavaScript to Build High-Performance Network Programs
Keywords: Node.js,JavaScript,Multithreading versus,The Node Programming
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 dev
剩余内容已隐藏,支付完成后下载完整资料
英语原文共 4 页,剩余内容已隐藏,支付完成后下载完整资料
资料编号:[595981],资料为PDF文档或Word文档,PDF文档可免费转换为Word
课题毕业论文、文献综述、任务书、外文翻译、程序设计、图纸设计等资料可联系客服协助查找。