深入浅出Node.js读书笔记:异步编程的优势与难点(4.2)

由于编程人员阅读思维习惯,同步I/O盛行了很多年,但同步问题会引起性能问题,于是我们开始使用多线程来解决性能问题。

但多线程存在CPU浪费的情况,比如线程之间切换,线程与线程之间锁,同步问题等等,会使CPU存在浪费情况。

下面来看看异步编程的优势与难点。

4.2.1 异步编程的优势

Node带来最大特性莫过于基于事件驱动的非阻塞I/O模型。非阻塞I/O可以使CPU与I/O并不互相依赖等待,让资源得到更好的利用。

由于事件循环模型需要对应海量请求,所有请求会作用于单线程上,需要防止任何一个计算耗费过多的CPU时间片。至于计算密集型,还是I/O密集型,只要计算不影响异步I/O的调度,那就不构成问题。

建议对CPU的耗用不要超过10ms,或者将大量的计算分解为诸多的小量计算,通过setImmediate()进行调度。只要合理利用Node的异步模型与V8的高性能,就可以充分发挥CPU和I/O资源的优势。

4.2.2 异步编程的难点

1.异常处理

过去我们处理异常时,通常使用try/catch/final语句块进行异常捕获,代码如下:

	try{
		JSON.parse(json);
	}catch(e){
		//TODO 
	}

但这对于异步编程而言并不适用。

之前文章提到,异步I/O的实现主要包含两个阶段:提交请求和处理结果。这两个阶段中间有事件循环的调度,两者彼此不关联。通常在第一步提交后,立马就返回了。

异步方法的定义如下:

	var async = function (callback) {
		process.nextTick(callback);
	}

进行如下的try/catch操作:

	try{
		async(callback);
	}catch(e){
		// TODO
	}

上述代码是无法对callback的异常进行捕获。

2.函数嵌套过深

例如在事务中存在多个异步调用的场景比比皆是。比如一个遍历目录的操作,其代码如下:

	fs.readdir(path.join(__dirname, '..'), function (err, files) { 
 		files.forEach(function (filename, index) { 
 			fs.readFile(filename, 'utf8', function (err, file) { 
 				// TODO
 			}); 
 		}); 
	});

对于上述场景,由于两次操作存在依赖关系,函数嵌套的行为也许情有可原。但是如果在readFile内再进行各种回调,那么就有些难以接受。

3.阻塞代码

对于刚入Javascript不久的开发者而言,该语言竟然没有sleep()这样的线程操作,唯独有setInterval()和setTimeout()这两个函数,而且这两个函数并不会阻塞后续代码持续执行。

4.多线程编程

Javascript是单线程的,单个进程无法充分利用多核CPU。但Node也提供了多进程的功能,后续章节会提到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值