Node.js vs Async /等待.net

有人可以解释/redirect我,Node.js的asynchronous模型(非阻塞线程)与任何其他语言(例如c#处理I / O的asynchronous方式)之间的区别是什么。 这看起来对我来说都是同一个模型。 请build议。

两种模型都非常相似。 有两个主要的差异,其中一个即将消失(对于“快”的一些定义)。

一个区别是Node.js是asynchronous的单线程,而ASP.NET是asynchronous的multithreading。 这意味着Node.js代码可以做一些简化的假设,因为所有的代码总是运行在同一个确切的线程上。 所以当你的ASP.NET代码await的时候,它可能会在不同的线程上恢复,这是由你来避免像线程本地状态。

但是,这种差异也是ASP.NET的一个优势,因为这意味着async ASP.NET可以通过扩展来实现服务器的全部function。 如果你考虑一个8核心的机器,那么ASP.NET可以同时处理8个请求的同步部分。 如果你把Node.js放在一个灵活的服务器上,那么通常会运行8个独立的Node.js实例,并添加一些像nginx或者一个简单的定制负载均衡器来处理该服务器的路由请求。 这也意味着如果你想让其他资源共享服务器(例如caching),那么你也需要把它们移出proc。

另一个主要的区别实际上是语言的差异,而不是平台。 JavaScript的asynchronous支持仅限于callback和承诺,即使你使用了最好的库,当你做任何不重要的事情时,你仍然会遇到非常尴尬的代码。 相比之下,C#/ VB中的async / await支持允许您编写非常自然的asynchronous代码(更重要的是,可维护的asynchronous代码)。

但是,语言差异正在消失。 JavaScript的下一个修订版本将引入生成器,这些生成器(和一个辅助库)将在Node.js中生成asynchronous代码,就像使用async / await一样自然。 如果你想现在玩“即将到来”的东西,发电机被添加到V8 3.19,它被卷入Node.js 0.11.2(不稳定的分支)。 传递--harmony--harmony-generators以显式启用生成器支持。

Node.js的asynchronous模型和C#的asynchronous/等待模型之间的区别是巨大的。 具有Node.js的asynchronous模型与C#和.Net中的asynchronous模型(称为基于事件的asynchronous模式(EAP))类似。 C#和.Net有3个asynchronous模型,你可以在asynchronous编程模式下阅读它们。 C#中最现代化的asynchronous模型是基于任务的,使用C#的asynchronous等待关键字,可以在基于任务的asynchronous模式下阅读 。 C#的async / await关键字使得asynchronous代码成为线性的,并且让你避免了“callback地狱”,这在任何其他编程语言中都要好得多。 你只需要尝试一下,之后就不会用其他方式做。 你只是编写消费asynchronous操作的代码,不用担心可读性,因为它看起来像你写的任何其他代码。 请观看这个video:

  1. asynchronous编程深度潜水
  2. 在ASP.NET中asynchronous
  3. 了解asynchronous和可怕的任务

请尝试在C#和Node.js中进行asynchronous操作以进行比较。 你会看到不同之处。

编辑 :由于Node.js V8 JavaScript引擎支持ECMAScript 6草案中定义的生成器,JavaScript代码中的“callback地狱”也可以很容易地避免。 它在JavaScript中带来了某种forms的asynchronous/等待生活

使用nodejs,所有的请求都进入事件队列。 Node的事件循环使用单个线程来处理事件队列中的项目,完成所有非IO工作,并发送到C ++线程池(使用javascriptcallback来asynchronouspipe理)所有IO绑定的工作。 C ++线程然后将其结果添加到事件队列中。

与ASP.NET的区别(两者首先适用于所有允许asynchronousIO的Web服务器)是:

  1. ASP.NET 为每个传入的请求使用不同的线程 ,因此您将获得上下文切换的开销
  2. .NET不会强制你使用asynchronous来完成IO绑定的工作,所以它不像nodejs那样习惯于使用IO绑定的API调用是事实上的asynchronous(带callback)
  3. .NET'“await-async”add在编译时添加一个步骤来添加“callback”,所以你可以编写线性代码(没有callback函数传递),与nodejs

networking上有很多地方描述节点的架构,但是这里有一些东西: http : //johanndutoit.net/presentations/2013/02/gdg-capetown-nodejs-workshop-23-feb-2013/index.html#1

Nodejs和.NET中的asynchronous之间的区别在于使用抢先式多任务处理用户代码。 .NET使用抢先式多任务处理用户代码,而Nodejs则不使用。

Nodejs使用内部线程池来提供IO请求,并使用单个线程来执行您的JS代码,包括IOcallback。

使用抢先式多任务(.NET)的后果之一是共享状态可以在执行堆栈时被另一堆执行改变。 在Nodejs中情况并非如此 – asynchronous操作的callback不能与当前正在执行的堆栈同时运行。 另一个执行堆栈在Javascript中不存在。 仅当当前的执行堆栈完全退出时,asynchronous操作的结果才可用于callback。 有,简单while(true); 挂起Nodejs,因为在这种情况下,当前堆栈不会退出,下一个循环永远不会启动。

为了理解这个差异,考虑两个例子,一个是js,一个是net。 var p = new Promise(function(resolve){setTimeout(resolve,500,“my content”);}); p.then(function(value){// … value ===“我的内容”

在这段代码中,你可以放心地在“开始”一个asynchronous操作之后放置一个处理程序,因为可以肯定的是,在整个当前调用堆栈退出之前,不会由asynchronous操作启动的callback代码执行。 callback在下一个周期中处理。 至于定时器callback,它们是一样的。 asynchronous计时器事件只是将callback处理放在队列中,以便在下一个周期中处理。

在.NET中是不同的。 没有周期。 有抢先多任务。

 ThreadPool.QueueUserWorkItem((o)=>{eventSource.Fire();}); eventSource.Fired += ()=>{ // the following line might never execute, because a parallel execution stack in a thread pool could have already been finished by the time the callback added. Console.WriteLine("1"); } 

下面是一个Hello World .NET a-la Nodejs代码,演示单线程的asynchronous处理,并使用线程池作为asynchronousIO,就像节点一样。 (.NET包括asynchronousIO操作的TPL和IAsyncResult版本,但是这个例子没有什么区别,总之一切都以一个线程池中的不同线程结束。

 void Main() { // Initializing the test var filePath = Path.GetTempFileName(); var filePath2 = Path.GetTempFileName(); File.WriteAllText(filePath, "World"); File.WriteAllText(filePath2, "Antipodes"); // Simulate nodejs var loop = new Loop(); // Initial method code, similar to server.js in Nodejs. var fs = new FileSystem(); fs.ReadTextFile(loop, filePath, contents=>{ fs.WriteTextFile(loop, filePath, string.Format("Hello, {0}!", contents), ()=>fs.ReadTextFile(loop,filePath,Console.WriteLine)); }); fs.ReadTextFile(loop, filePath2, contents=>{ fs.WriteTextFile(loop, filePath2, string.Format("Hello, {0}!", contents), ()=>fs.ReadTextFile(loop,filePath2,Console.WriteLine)); }); // The first javascript-ish cycle have finished. // End of a-la nodejs code, but execution have just started. // First IO operations could have finished already, but not processed by callbacks yet // Process callbacks loop.Process(); // Cleanup test File.Delete(filePath); File.Delete(filePath2); } public class FileSystem { public void ReadTextFile(Loop loop, string fileName, Action<string> callback) { loop.RegisterOperation(); // simulate async operation with a blocking call on another thread for demo purposes only. ThreadPool.QueueUserWorkItem(o=>{ Thread.Sleep(new Random().Next(1,100)); // simulate long read time var contents = File.ReadAllText(fileName); loop.MakeCallback(()=>{callback(contents);}); }); } public void WriteTextFile(Loop loop, string fileName, string contents, Action callback) { loop.RegisterOperation(); // simulate async operation with a blocking call on another thread for demo purposes only. ThreadPool.QueueUserWorkItem(o=>{ Thread.Sleep(new Random().Next(1,100)); // simulate long write time File.WriteAllText(fileName, contents); loop.MakeCallback(()=>{callback();}); }); } } public class Loop { public void RegisterOperation() { Interlocked.Increment(ref Count); } public void MakeCallback(Action clientAction) { lock(sync) { ActionQueue.Enqueue(()=>{clientAction(); Interlocked.Decrement(ref Count);}); } } public void Process() { while(Count > 0) { Action action = null; lock(sync) { if(ActionQueue.Count > 0) { action = ActionQueue.Dequeue(); } } if( action!= null ) { action(); } else { Thread.Sleep(10); // simple way to relax a little bit. } } } private object sync = new object(); private Int32 Count; private Queue<Action> ActionQueue = new Queue<Action>(); }