Node.js和CPU密集型的请求

我已经开始修补Node.js的HTTP服务器,真的很喜欢写服务器端的JavaScript,但有些东西让我无法使用Node.js为我的Web应用程序。

我了解整个asynchronousI / O概念,但是我对程序代码非常耗费CPU的边缘情况(如image processing或sorting大型数据集)感到有些担忧。

据我所知,服务器将非常快速的简单的网页请求,如查看用户列表或查看博客文章。 但是,如果我想编写非常CPU密集的代码(例如pipe理员后端)来生成graphics或调整成千上万的图像,请求将非常缓慢(几秒钟)。 由于这段代码不是asynchronous的,所以在这几秒钟内到达服务器的每个请求将被阻塞,直到我的请求缓慢完成。

一个build议是使用Web Workers进行CPU密集型任务。 但是,恐怕networking工作者会因为包含一个单独的JS文件而难以编写干净的代码。 如果CPU密集型代码位于对象的方法中,该怎么办? 对于CPU密集型的每种方法来说,写一个JS文件是非常糟糕的。

另一个build议是产生一个subprocess,但是这使得代码更加不可维护。

任何build议来克服这个(知觉)的障碍? 如何在确保CPU繁重任务执行asynchronous的同时,如何使用Node.js编写干净的面向对象的代码?

你需要的是一个任务队列! 将长时间运行的任务移出networking服务器是件好事。 保持每个任务在“独立的”js文件中促进了模块化和代码重用。 它迫使你考虑如何构build你的程序,以便于长期debugging和维护。 任务队列的另一个好处是可以用不同的语言编写工作人员。 只需popup一个任务,完成工作,并将回复写回。

像这样的https://github.com/resque/resque

这里有一篇关于为什么他们build立它的文章github http://github.com/blog/542-introducing-resque

这是误解了Web服务器的定义 – 它只能用来与客户“交谈”。 重载任务应该委托给独立程序(当然也可以用JS编写)。
你可能会说这是脏的,但我向你保证,一个Web服务器进程停留在调整图像大小更糟(甚至让Apache说,当它不阻止其他查询)。 不过,您可以使用通用库来避免代码冗余。

编辑:我想出了一个比喻; networking应用程序应该作为一个餐厅。 你有服务员(networking服务器)和厨师(工作人员)。 侍者与客户联系,并做简单的任务,如提供菜单或解释一些菜是否素食。 另一方面,他们把更难的任务交给厨房。 因为服务员只做简单的事情,他们反应迅速,厨师可以专心工作。

这里的Node.js将是一个单一的,但非常有才华的服务员,可以一次处理很多请求,而Apache将是一群只能处理一个请求的服务员。 如果这个Node.js服务员开始做饭,这将是一场直接的灾难。 尽pipe如此,烹饪还可能耗尽大量的Apache服务员,并没有提到厨房的混乱和响应性的逐渐下降。

几个你可以使用的方法。

正如@Tim所指出的那样,您可以创build一个asynchronous任务,它位于您的主要服务逻辑之外或与之并行。 取决于你的具体要求,但即使是cron也可以作为排队机制。

WebWorkers可以为你的asynchronous进程工作,但目前不支持node.js。 有几个扩展提供支持,例如: http : //github.com/cramforce/node-worker

你仍然可以通过标准的“require”机制重新使用模块和代码。 您只需确保向工作人员发送最初的信息即可传递处理结果所需的所有信息。

你不希望你的CPU密集的代码执行asynchronous,你希望它并行执行。 您需要从提供HTTP请求的线程中获取处理工作。 这是解决这个问题的唯一方法。 使用NodeJS的答案是集群模块 ,用于产生subprocess来完成繁重的工作。 (AFAIK节点没有任何线程/共享内存的概念;它是进程或没有)。 你有两个select你如何构build你的应用程序。 您可以通过产生8个HTTP服务器并在subprocess上同步处理计算密集型任务来获得80/20解决scheme。 这样做相当简单。 你可以花一个小时在这个链接阅读有关它。 事实上,如果你只是把这个链接顶部的示例代码撕掉,那么你会得到95%的回报。

另一种构造方法是build立一个作业队列,并在队列中发送大的计算任务。 请注意,与作业队列相关的IPC有很多开销,所以这只在任务明显大于开销时才有用。

我很惊讶,其他答案都没有提到集群。

背景:asynchronous代码是暂停的代码,直到其他地方发生某些事情 ,代码唤醒并继续执行。 I / O是一个非常常见的情况,其中一些缓慢的事情必须发生在其他地方。

如果你的处理器负责完成这个工作,asynchronous代码就没用了。 “计算密集型”任务正是如此。

现在,看起来asynchronous代码是有利可图的,但事实上这是非常普遍的。 这对于计算密集型任务来说并不有用。

例如,等待I / O是一种总是在Web服务器中发生的模式。 连接到服务器的每个客户端都获得一个套接字。 大多数时候sockets是空的。 你不想做任何事情,直到一个套接字接收到一些数据,在这一点上你想处理请求。 在引擎盖下,像Node这样的HTTP服务器正在使用事件库(libev)来跟踪成千上万个打开的套接字。 操作系统通知libev,然后libev在其中一个套接字获取数据时通知NodeJS,然后NodeJS在事件队列中放置一个事件,并且您的http代码在这一点上触发并逐个处理事件。 事件不会被放在队列中,直到套接字有一些数据,所以事件不会等待数据 – 它已经在那里了。

单线程基于事件的Web服务器在瓶颈等待一堆大部分为空的套接字连接时是有意义的,并且您不需要为每个空闲连接创build一个完整的线程或进程,而且您也不希望轮询您的250kfind下一个有数据的套接字。