我刚刚观看了以下视频:Node.js 简介,但仍然不明白如何获得速度优势。
主要是,Ryan Dahl(Node.js 的创建者)曾说过 Node.js 是基于事件循环的,而不是基于线程的。线程很昂贵,只能留给并发编程专家使用。
随后,他展示了 Node.js 的架构堆栈,该堆栈具有底层 C 实现,内部有自己的线程池。所以很明显 Node.js 开发人员永远不会启动他们自己的线程或直接使用线程池......他们使用异步回调。我就这么理解。
我不明白的是 Node.js 仍然在使用线程……它只是隐藏了实现,所以如果 50 个人请求 50 个文件(当前不在内存中)那么这将如何更快,那么不需要 50 个线程?
唯一的区别是,由于它是在内部管理的,Node.js 开发人员不必编写线程详细信息,但在其下面仍然使用线程来处理 IO(阻塞)文件请求。
那么,您不是真的只是解决一个问题(线程)并在该问题仍然存在时隐藏它:主要是多线程、上下文切换、死锁......等等?
一定有一些细节我还是不明白。
实际上这里有一些不同的东西被混为一谈。但它始于线程真的很难的模因。因此,如果它们很难,您更有可能在使用线程时 1) 因错误而中断和 2) 尽可能高效地使用它们。(2) 是你要问的那个。
想想他给出的一个例子,一个请求进来,你运行一些查询,然后对结果做一些事情。如果您以标准程序方式编写它,代码可能如下所示:
result = query( "select smurfs from some_mushroom" ); // twiddle fingers go_do_something_with_result( result );
如果传入的请求导致您创建一个运行上述代码的新线程,那么您将有一个线程坐在那里,在query()运行时什么都不做。(根据 Ryan 的说法,Apache 正在使用单个线程来满足原始请求,而 nginx 在他所说的情况下优于它,因为它不是。)
query()
现在,如果你真的很聪明,你会以一种环境可以在运行查询时执行其他操作的方式来表达上面的代码:
query( statement: "select smurfs from some_mushroom", callback: go_do_something_with_result() );
这基本上就是 node.js 正在做的事情。你基本上是在装饰——以一种方便的方式,因为语言和环境,因此关于闭包的要点——你的代码以这样一种方式,即环境可以聪明地知道什么运行,什么时候运行。这样一来,node.js 并不 新鲜 ,因为它发明了异步 I/O(不是任何人声称有这样的东西),但它的新颖之处在于它的表达方式有点不同。
注意:当我说环境可以很聪明地知道什么时候运行时,特别是我的意思是它用来启动一些 I/O 的线程现在可以用来处理一些其他请求,或者一些可以完成的计算并行,或启动其他一些并行 I/O。(我不确定节点是否足够复杂,可以为同一个请求启动更多工作,但你明白了。)