Con*_*Del 21 multithreading asynchronous node.js node-modules
只是想知道是否有人可以给我比较这些模块之间的权衡以处理异步事件.具体来说,我有兴趣知道使用Async而不是Fibers.promise的原因,我现在至少在我的测试代码中使用得非常广泛.特别是,我在Fibers.promise中看到的一个主要优点是我可以保持堆栈链前面分叉,使其可以使用try { } catch { } finally,并且还允许我在处理请求后确保响应结束.
有人使用Q_oper8吗?我在另一页上发现了这个,只是想知道它是否已经死了或者我应该检查一下.
小智 37
我从来没有听说过Q_oper8,所以我不能评论它,但我会从另一个方向来看这个.我听说过async first和Fiber(及其助手库)第二,我实际上并不喜欢后者.
Fiber通过编译的Fiber本机方法向Javascript引入了协同例程的概念,该方法接管传递给它的Javascript代码的解释,拦截调用yield以跳回到等待的协同例程.
这对您来说无关紧要,但如果您需要在团队中工作,您必须向您的成员传授这个概念(或者希望他们对其他语言的概念有经验,比如Go).
因此,为了使用Fiber或其上编写的任何库,您必须首先为您的平台本地编译它.我不使用Windows,但请注意Windows上不支持光纤,因此限制了您自己的库的实用程序.这意味着你将不会被找到通用的Node.js写在光纤库在所有(你可能不会有,反正,因为它增加了一个昂贵的编译步骤是你会以其他方式与异步避免).
这意味着您使用Fiber编写的任何代码都无法在浏览器中运行,因为您无法将本机代码与浏览器混合(我也不会像浏览器用户那样),即使您编写的所有内容都是"Javascript" "(它是语法上的Javascript,但在语义上不是).
虽然"回调地狱"的视觉效果可能不那么令人满意,但是继续传递风格在Co-Routines上确实有一个非常好的事情 - 你确切地知道调用堆栈中出现问题的位置并且可以向后追踪.Co-Routines在程序中的多个点进入函数,并且可以退出三种调用:return,throw并且yield(),后者也是返回点.
使用协同例程,您可以在两个或多个同时运行的函数之间执行交叉执行,并且可能在事件循环中同时运行多个协同例程.使用传统的回调,您可以保证在执行所述函数期间函数的外部作用域是静态的,因此您只需要在需要时检查这些外部变量一次.协同例程需要在每个之后运行这些检查yield()(因为它与原始协同例程的使用将被转换为真实Javascript中的回调链).
基本上,我认为协同例程概念更难以使用,因为它必须存在于 Javascript事件循环内部,而不是实现它的方法.
实际上,这就是"更糟 - 更好"的想法.而不是扩展Javascript语言来尝试摆脱它的疣(并在我看来创建新的疣),Async是一个纯粹的Javascript解决方案来掩盖它们,就像化妆一样.
Async函数描述了需要跨越事件循环障碍的不同类型的逻辑流,并且库涵盖了实现该逻辑所需的回调代码的实现细节,并且您只需提供它应该以大致线性顺序运行的函数它们将在事件循环中执行.
如果你愿意在async方法的参数周围删除第一个缩进级别,那么与Co-Routines相比没有额外的缩进,只有少量额外的function(callback) {声明行,如下所示:
var async = require('async');
var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
async.forEach(someArray,
function(number, callback) {
//Do something with the number
callback();
}, function(err) {
//Done doing stuff, or one of the calls to the previous function returned an error I need to deal with
});
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您知道代码所使用的所有变量只有在代码运行之前才会被更改,如果它们没有被代码更改,那么您可以更容易地调试,并且只有一个"返回"机制:callback().您可以在成功时回调任何内容,也可以在出现问题时将回调传递给错误.
上面的例子使代码重用变得困难,但并非如此.您始终可以将命名函数作为参数传递:
var async = require('async');
// Javascript doesn't care about declaration order within a scope,
// so order the declarations in a way that's most readable to you
async.forEach(someArray, frazzleNumber, doneFrazzling);
var someArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function frazzleNumber(number, callback) {
// Do something to number
callback();
}
function doneFrazzling(err) {
// Do something or handle error
}
Run Code Online (Sandbox Code Playgroud)
异步模块不鼓励使用命令式流控制,并鼓励(对于跨越事件循环的部分)需要使用函数进行流控制.
功能风格的优点是你可以轻松地重复使用循环体或条件,并且你可以创建新的控制流"动词",以更好地匹配你的代码流(通过它的存在证明async library),类似于async.auto实现函数调用顺序的依赖图解析的控制流方法.(您指定一系列命名函数并列出它依赖于执行的其他函数,如果有的话,auto首先运行"独立"函数,然后运行可以根据其依赖函数何时完成运行的下一个函数.)
您可以根据问题的逻辑编写代码,而不是编写代码以适应您的语言所指示的命令式样式,并实现"粘合"控制流程以实现它.
由于扩展Javascript语言的本质,Fibre无法在Node.js中开发大型生态系统,特别是当Async在外观部门获得80%的方式时,并且在Javascript中没有其它的共同例程缺点.
B T*_*B T 12
简短的回答:
请注意,这些都没有提供"线程",所以没有人可以说做多线程(虽然也有一个node.js扩展名:threads_a_gogo).
异步和光纤/期货是解决同一问题的不同方法:管理异步解析依赖关系.异步似乎比试图解决这个问题的许多其他图书馆有更多的"花里胡哨",在我看来,它更糟糕(更多的认知开销 - 即更多的废话学习).
在javascript中,基本的异步性如下所示:
asyncCall(someParam, function(result) {
useThe(result);
});
Run Code Online (Sandbox Code Playgroud)
如果你的情况需要的不仅仅是基本的异步性,比如你需要两个异步调用的结果,你可能会这样做:
asyncCall1(someParam, function(result0) {
asyncCall2(someParam, function(result1) {
use(result0, result1);
}
});
Run Code Online (Sandbox Code Playgroud)
已经开始看起来像回调地狱.它也是低效的,因为第二个调用正在等待第一个调用完成,即使它不依赖于它,更不用说代码甚至没有做任何合理的错误处理.Async提供了一种解决方案,可以更有效地编写它:
async.parallel([
function(callback) {
asyncCall1(someParam, function(result0) {
callback(null,result0);
},
function(callback) {
asyncCall1(someParam, function(result1) {
callback(null,result1);
},
}
],
function(err, results) {
use(results[0], results[1]);
});
Run Code Online (Sandbox Code Playgroud)
所以对我而言,这比回调地狱还要糟糕,但我认为对他自己而言.尽管它很难看,它允许两个调用同时发生(只要它们进行非阻塞IO调用或类似的事情).Async有更多用于管理异步代码的选项,因此如果您有兴趣,请查看文档.
协同程序Fibers模块包括一个期货库,它使用协程将异步事件重新注入当前的延续(future.wait()).
Fibers与大多数其他期货库不同,因为它允许当前延续等待异步事件 - 这意味着它不需要使用回调以便从异步请求中获取值 - 允许异步代码变为同步等.阅读有关协程的更多信息.
Node.js有像readFileSync这样的函数,它可以让你在获取文件时在线等待函数.这不是通常在javascript中完成的东西,并且不是可以用纯JavaScript编写的东西 - 它需要像Fibers这样的扩展.
回到上面的相同异步示例,这就是光纤/期货的样子:
var future0 = asyncCall1(someParam);
var future1 = asyncCall2(someParam);
use(future0.wait(), future1.wait());
Run Code Online (Sandbox Code Playgroud)
这非常简单,就像那里的异步混乱一样高效.它以优雅有效的方式避免了回调地狱.但是有(次要的)缺点.大卫·埃利斯夸大了许多缺点,所以我将重复这里唯一有效的一个:
由于Fibers是node.js扩展,它将与浏览器不兼容.这将使得使用node.js服务器和浏览器的共享代码无法使用光纤.然而,有你想要的服务器(文件系统,数据库,网络电话)的最异步代码一个有力的论据是不上的浏览器(Ajax调用)你想相同的代码.也许超时会发生碰撞,但这似乎就是这样.
除此之外,streamline.js项目还能够弥补这一差距.看起来它有一个编译过程,可以使用同步和期货将streamline.js代码转换为使用回调样式的纯javascript,类似于现在不支持的Narrative Javascript.Streamline.js可以在幕后使用几种不同的机制,一种是node.js Fibers,另一种是ECMAScript 6生成器,最后一种是转换为我已经提到的回调式javascript.
这个似乎是一个有效的,如果轻微的抱怨.即使您只是计划使用光纤/期货,而不是使用协同程序,但由于意外的功能退出(和入口)点,可能仍会出现令人困惑的上下文切换.
这可能是纤维最主要的问题,因为它有可能(但不太可能)引入难以理解的错误.基本上,因为光纤yield可能导致一组代码临时退出到另一个未确定的函数,所以可能会读取或引入某些无效状态.有关详细信息,请参阅此文章.就我个人而言,我认为纤维/期货和类似结构的令人难以置信的清洁度非常值得这个罕见的阴险错误.更糟糕的错误是由糟糕的并发代码引起的.
有许多图书馆实施期货,其概念可称为"期货","延期对象"或"承诺".这包括async-future,streamline.js,Q,when.js,promiscuous,jQuery的延迟,coolaj86的未来,kriszyp的承诺和Narrative Javascript等库.
其中大多数使用回调来解决期货,这解决了Fibers引入的许多问题.然而,它们并不像纤维/期货那样干净,因为它们比Async更清洁.以下是使用我自己的异步未来的相同示例:
var future0 = asyncCall1(someParam);
var future1 = asyncCall2(someParam);
Future.all([future0, future1]).then(function(results) {
use(results[0], results[1])
}).done()
Run Code Online (Sandbox Code Playgroud)
Q_oper8真的是一个不同的野兽.它使用进程池在队列中运行作业.由于javascript是单线程*,并且javascript没有可用的本机线程,因此进程是利用node.js中多个处理器的常用方法.Q_oper8旨在替代使用node.js的child_process模块管理进程.
| 归档时间: |
|
| 查看次数: |
9627 次 |
| 最近记录: |