小弟Node.js新手。
看了一些介绍,感觉大家都觉得,在Node.js中,异步“高效性”都体现在可以迅速响应用户的请求并做出反应。
但假如用户请求的内容需要有数据库查询这样的操作,I/O虽然未阻塞,但是必须得等数据表查完了,才能给用户发送完整的http response报文啊,在此之前用户的浏览器应该还是没有任何响应啊?
请问在这一点上,Node.js的迅速体现在哪里?
伊谢尔伦2017-04-17 11:14:55
@1000copy 的回答废话太多了。
大部分 Web 应用的瓶颈都在 IO, 即读写磁盘,读写网络,读写数据库。使用怎样的策略等待这段时间,就成了改善性能的关键点。
何谓「最高效地利用时间」?比如现在有两个不相关的数据库查询,在 PHP 中通常会先执行一个,执行完成后再执行第二个(总时间是 a + b). 显然这不是最高效的,应该同时执行两个查询,时间是 max(a, b).
Python 和其他支持多线程的语言的问题就在于,在语言层面,程序员很难告诉虚拟机,应当将两个操作同时执行,即使有办法,也相当麻烦,大多数人懒得去用(也不值得去用)。而因为 Node.js 没有历史包袱,强制所有的 IO 操作必须通过回调函数来通知,因此在 Node 里可以非常灵活地让两个查询同时执行,节省时间。
黄舟2017-04-17 11:14:55
你提到的单客户上的时间上的效率,答案确实是不能提升。因为真正的时间压力不在node.js ,而是数据库服务器。但是,作为服务器软件,考量单客户速度,其实无意义。因为服务器,要考量的是并发用户数上来后,编程模型可以不变,仅仅增加设备和配置就可以支持。所谓的可伸缩性。
社区内广泛存在的node.js 高效的说法,我认为是有误导之嫌疑的:)。充斥着node.js 社区的骄傲和对老派并发模型的不肖。
很简单,你说高效是和谁比较呢?没有对比主体的高效,都是耍流氓。所以,我觉得nodejs 的默认对手,当然是传统的并发模型的web server,如apache。
服务器的东西,必然是多线索运行的。和apache,iis不同的地方在于:
当然传统的,不是简单地一对一,来一个request,iis 可能new一个新线程,也可能在线程池(进程池)内找到一个现成的。具体就要看web garden 的配置了。
其实老的方式也不是罪恶之源了。用户代码存在于多个线程中,只要不访问共享资源,或者这个共享资源考虑到了多线程并发的情况,都是OK的。
以我们一个产品的.net 代码为例,一直运行良好。直到又一次把web garden配置为>1 ,结果发生了找不到软件狗的问题。因为我们的软件狗就是一个没有考虑并发的单机软件狗。我们自己的代码更牛,是一个静态类(静态类变量是全局共享的,在多线程情况下,访问同一个静态类变量就会发生经典的多线程重入问题)。
当然,关系数据库本身也是共享资源,可是人家考虑了多线程并发了(这是当然的)
node.js的设计者,采用了新的并发模型,对于用户的效果显然的。不管访问什么共享资源,都不必考虑重入问题。因为应用程序开发者根本就没有多线程。如果有共享资源,那么有高级的程序员去封装库。如果有多线程问题,那么一定是库的问题。真的是把应用程序员为视为笨蛋的节奏啊。真的是库程序员解救世界啊。很残酷的是,据我的观察,他是对的:————)
就意味着所有的库,最终和用户线程(唯一的)打交道的方法都必须重新考量,重新做,原来的所有现存代码,都需要重新翻新(至少是需要重新包装)。这就是他的伟大(牛逼)之处。真敢干。也是他不选择lua,python来实现的原因,因为js在服务器端没有历史包袱,直接新写代码即可,不太需要重新封装现有的库。如果因此就说Node.js 更加高效(笑话:),我不敢苟同。
都是我的个人理解,欢迎搬砖。
因此做一个牛逼哄哄的总结:
node.js 的优势在于:以不需要应用程序员引入线程的情况下,以不低于现在已有方案的效率处理客户访问。
怪我咯2017-04-17 11:14:55
传统的服务器IO阻塞是最大的瓶颈,假设一个请求来了,要茶数据库,返回,整个过程需要1秒。应用服务器启动100个线程作为线程池,那么在100个并发请求的情况下,客户端基本都可以在1秒得到结果,但是如果并发数继续增大,客户端就需要排队了。这是传统的IO阻塞模型。
Node和Nginx属于IO非阻塞模型,无论来多少个请求都不阻塞,而是立刻dispatch给后台的处理线程去处理,主线程立刻可以处理下一个请求。Node在处理请求的时候根本不需要线程池的概念,在大并发的时候效率的优势就显现出来了。