Node.js的人性化
Node.js的人性化
NODE要比JavaScript在服务器上运行得多多了。
这是Node的聪明之处,对吧!现在你可以同时写服务器端和客户端的JavaScript。
当你不得不从客户端转移到服务器端或反过来,这个过程极其痛苦,一部血泪史。如今,你再也不用再埋头苦读,穿梭于不同环境之间了。
<br />
希望各位能注意到我的讽刺。
Node使用JavaScript仅仅是一个第三方点,有舍有得(对有些人有利,有些人有害)。可以肯定的是,这对于Node的成功有很大贡献,但是太多了,以致于Node的根本点和目的会经常丢失。如果这对你来说是显而易见的,那么你可以不用读此文了。
说你喜欢Node是因为可以在服务器端写JavaScript代码,就像说你喜欢红色 Lotus Elises是因为它们是被漆成红色一样。不是每一个人都喜欢红色,而且就算是每个人都喜欢,这也不是让这个车如此受欢迎的最重要理由。
NODE与目前的动态语言现状有着根本区别。它是由对效率的极度痴迷而产生的。人们对线程与连接之间经典1对1模式的不满,让它有能力处理显著增长的用动态语言为web应用写的并发等级。
###阻塞和IO问题
应用一般都是由数据库,文件系统,网络,或这些介质结合起来来传送/接收数据的。通常,这些信息的传输速度比直接在内存中操作的速度要慢。CPU的过量使用似乎不是你的问题。
第二个问题是我们开始处理问题的方法。从历史的角度上理解电脑,我们能有序地思考。这就是电脑思考问题的方式,对吗?你提供一大堆的指令,然后电脑从上到下有序的执行。你的第一个程序大概像下面这样子:
// print
console.log("Enter your name: ");
// block execution to retrieve data
// keeping the process tied up awaiting the
// data’s return
var name = console.read();
// manipulate data and report
console.log("Hello " + name + “!”);
<br />
但是如果你能以非阻塞方式做的话
// print
console.log("Enter your name: ");
// make a request for the data, but allow the process to
// be free to do other things, providing a bit of code
// to run when the data is retrieved.
console.read(
// When we are notified we have a
// response, manipulate data and report
function(err, name) {
console.log("Hello " + name + “!”);
}
);
<br /> 让你的进程阻塞、等待数以百万计的时钟周期将很浪费时间和资源。为了处理额外的请求,某些情况下你必须使用进程管理器来管理这些线程。为了让web逐渐更具媒体交互性,我们不断地减少每个请求的大小,虽然这些不断增加的请求是由每个单独的客户端发起的。这让为什么请求与进程之间1对1关系很难衡量变得很明显。
站在历史的角度上,我们让自己能够更简单地以第一种风格来说服我们的程序,但我认为第二种方式也是一样的,如果没有太多,像人类一样进行敏锐的判断。
###像人类一样思考
作为人类,你知道信息流的异步本性。你凭直觉知道,这仅仅只是没有效果和实用性来阻止每次你需要检索或传达信息时所做的所有事情。
作为一个开发者,你每次向经理或股东询问一个项目的详细情况时,你会简单地坐着然后安静地等待回复吗?不,当然不会。你移步到下一个你能取得进展的事情上,欺骗一个单方面很充分的重要任务。一旦信息复原,就继续相关任务。
举个更通俗的例子,你在开车,旁边是你的朋友,你需要知道明天的天气情况。你会刹车、不管交通秩序就面向你的朋友问他明天天气吗?你会沉默的等待(除非后面的人按喇叭)直到他查询完天气?当然不会,当他告诉你天气情况时,你会继续和他聊别的东西。
在这种方式下,Node的非阻塞/异步模型在第一次传递时并不需要变得异质。
###为什么不用线程
线程困难,繁重,大材小用。
他们确实解决了平行的基本问题,但他们提出一个围绕着线程安全和易变性的全新问题。如果要实施的话,对于动态语言来说它们通常很复杂且很难解决。
在Node中,除了你的代码,所有东西都平行运行着。
对于你来说,所有事情都可以通过平行来解决。但是由于你的代码永远不会平行的运行,且通常都在单线程中,线程安全和易变性就没有了。这给一般用例的平行化带来了好处,不需要给开发者额外的复杂度。
我认为Node处理平行化的方法再次反应出我们人类过程思考的方式,并不是并行的,但是高效的多任务。
###某某语言也有非阻塞服务
我确信肯定有,当你想用不会导致阻塞的第三方包模型时,它可能是有用的。非阻塞被开发社区很哲学化地应用了。这是规则,不是例外。
此外,围绕着异步性的事件循环和支持性基础通过低级语言很好的实现了(V8,libev,libeio等等)。其他许多动态语言的非阻塞服务将利用这样的库,但创造性的是用它们的动态语言来实现。在这种情况下,当与Node的实现相比时,性能是要特别关注的。
所有语言或平台都是有折衷的,但希望我的想法能让Node在作为实用性问题解决方案和有意思的学术实践两方面都更具独特之处。
<br /> By Jonathan D. Johnson
From:http://jondavidjohn.com/nodejs-is-human/?utm_source=ourjs.com
Node.js 的人性化
Node.js 是一种在服务器端运行 JavaScript 的环境,这使得开发者可以统一编写前端和后端代码。尽管这一特性吸引了很多人,但它的成功并非仅仅因为这一点。实际上,Node.js 在处理并发和 I/O 操作上的高效性才是其核心优势。
阻塞和 I/O 问题
无论是在 Web 应用还是其他类型的应用中,I/O 操作往往是性能瓶颈。例如,数据库查询、文件系统读写、网络请求等都会消耗大量时间。传统的编程方式通常是阻塞式的,即在执行某项 I/O 操作时,程序会暂停等待结果返回。这种方式会导致资源浪费和性能下降。
让我们看一个简单的示例代码:
// 阻塞式代码
console.log('Enter your name:');
const name = console.read(); // 假设 console.read() 是一个阻塞函数
console.log(`Hello ${name}!`);
在这个例子中,程序会暂停等待用户输入,直到输入完成才会继续执行后续代码。这种方式在处理大量并发请求时非常低效。
相比之下,非阻塞式代码可以更好地利用 CPU 和内存资源:
// 非阻塞式代码
console.log('Enter your name:');
console.read(function(err, name) {
if (err) throw err;
console.log(`Hello ${name}!`);
});
这里,console.read()
方法接受一个回调函数作为参数。当 I/O 操作完成后,回调函数会被调用,从而避免了阻塞主线程。这种方式使程序能够同时处理多个请求,提高了整体性能。
像人类一样思考
人类在处理任务时,通常会利用多任务处理的能力。例如,在等待天气预报的同时,我们可能会继续开车或做其他事情。这种异步处理方式同样适用于编程。Node.js 使用事件驱动和非阻塞 I/O 模型,使得开发者能够以更自然的方式编写代码。
function getWeather(callback) {
setTimeout(() => {
const weather = 'Sunny';
callback(weather);
}, 2000); // 模拟异步操作
}
console.log('Checking the weather...');
getWeather((weather) => {
console.log(`The weather is ${weather}.`);
});
在这个例子中,getWeather
函数模拟了一个耗时的异步操作(例如网络请求),并通过回调函数返回结果。主程序不会阻塞等待结果,而是继续执行后续代码。这种方式使得程序更加高效和响应迅速。
为什么不用线程
线程虽然可以解决并行处理的问题,但同时也引入了线程安全和状态管理的复杂性。Node.js 采用单线程模型,所有的 I/O 操作都是异步的。这意味着开发者无需担心线程同步和状态共享的问题,从而简化了编程模型。
// 单线程示例
console.log('Start processing...');
setTimeout(() => {
console.log('Processing completed.');
}, 1000);
console.log('Continuing other tasks...');
在这个例子中,setTimeout
函数模拟了一个耗时的操作。尽管这个操作会延迟执行,但主线程不会阻塞,可以继续执行其他任务。这种方式使得 Node.js 能够高效地处理并发请求,而无需复杂的线程管理。
结论
Node.js 之所以“人性化”,是因为它采用了与人类思维方式相匹配的编程模型。通过非阻塞 I/O 和事件驱动架构,Node.js 让开发者能够以更自然、更高效的方式编写代码。尽管它并不是唯一支持非阻塞 I/O 的语言,但其独特的设计使其在处理并发和 I/O 密集型任务时表现出色。
…
Node.js 的人性化体现在其非阻塞和事件驱动的设计上,使得开发者能够更自然地编写高效、高性能的代码。这种设计不仅提高了程序的响应速度,还减少了资源的浪费。
非阻塞 I/O
Node.js 通过非阻塞 I/O 操作解决了传统阻塞方法中的性能瓶颈问题。例如,在处理用户输入时,阻塞方法会占用大量时间等待数据输入:
// 阻塞方法
console.log('Enter your name:');
var name = console.read();
console.log('Hello ' + name + '!');
而非阻塞方法允许程序在等待数据时继续执行其他任务:
// 非阻塞方法
console.log('Enter your name:');
console.read(function(err, name) {
if (err) throw err;
console.log('Hello ' + name + '!');
});
事件驱动模型
Node.js 使用事件驱动模型来处理异步操作。通过这种方式,我们可以编写更加直观的代码,就像人类处理事务的方式一样。例如,监听 HTTP 请求的事件:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
在这个例子中,createServer
方法会监听 HTTP 请求,并在接收到请求时触发回调函数。这种非阻塞和事件驱动的设计使得 Node.js 在处理大量并发请求时表现出色。
线程与性能
Node.js 单线程模型避免了复杂的线程同步问题,同时也减少了线程上下文切换带来的开销。尽管多线程可以提高并发处理能力,但在实际应用中往往需要复杂的锁机制来保证线程安全,增加了开发难度和维护成本。
总之,Node.js 的非阻塞和事件驱动设计使其在处理高并发场景时表现优异,同时也降低了开发者的认知负担,使得编程体验更加人性化。