Node.js vs Async/await in .net



有人可以解释/重定向我吗,node.js的异步模型(非阻止线程)与任何其他语言之间有什么区别,例如C#的处理I/O的异步方法。在我看来,这两者都是相同的模型。请建议。

两个模型都非常相似。有两个主要区别,其中一个即将消失(对于"很快"的某些定义)。

一个区别是node.js是异步的单线程,而asp.net是异步的多线程。这意味着Node.js代码可以做出一些简化的假设,因为您的代码始终在相同的精确线程上运行。因此,当您的ASP.NET代码await s时,它可能会在不同的线程上恢复,这取决于您避免使用诸如线程 - 本地状态之类的事情。

但是,这种差异也是ASP.NET的优势,因为这意味着async ASP.NET可以按开箱即用,直到您的SEVER的全部功能。如果您考虑一台8核机器,则ASP.NET可以同时处理(同步部分)8请求。如果将node.js放在汤中,则通常运行8个单独的node.js实例,并添加诸如NGINX或简单的自定义负载平衡器之类的内容,该均衡器处理该服务器的路由请求。这也意味着,如果您希望其他资源共享服务器范围内(例如,缓存),那么您也需要将它们移动到下方。

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

但是,语言差异正在消失。JavaScript的下一个修订版将介绍生成器(与辅助库一起)将在Node.js中制作异步代码,就像今天使用async/await一样自然。如果您想现在使用"即将到来"的东西,则在V8 3.19中添加了发电机,该v8 3.19被滚入node.js 0.11.2(不稳定的分支)。通过--harmony--harmony-generators明确启用发电机支持。

node.js的async模型与c#'s async/等待之间的差异模型很大。具有node.js的异步模型类似于C#和.NET中的 old async模型,称为基于事件的异步模式(EAP)。C#和.NET具有3种异步模型,您可以通过异步编程模式阅读有关它们的信息。C#中最现代的async模型是基于任务的C#'s async 等待关键字,您可以在基于任务的异步模式下阅读有关它的信息。c#'s async /等待关键字使异步代码线性线性,让您避免"呼叫"地狱吧。比其他任何编程语言都要好得多。您需要尝试一下,然后您永远不会以其他方式进行操作。您只需编写消耗异步操作的代码,而不必担心可读性,因为它看起来像您编写任何其他代码。请观看此视频:

  1. 异步编程深水潜水
  2. ASP.NET中的异步
  3. 了解异步和期待的任务
而且,请尝试在c#中做一些异步,然后进行node.js进行比较。您会看到区别。

编辑:由于Node.js V8 JavaScript引擎支持发电机,因此在Ecmascript 6草稿中定义了"回调"地狱。在JavaScript中,也可以轻松避免。它在JavaScript中带来了某种形式的异步/等待生命

使用nodejs,所有请求都在事件队列中进行。Node的事件循环使用单个线程来处理事件队列中的项目,进行所有非IO工作,然后发送到C ThreadPool(使用JavaScript回调来管理异步)工作。然后,C 线程添加到事件队列的结果。

ASP.NET的差异(两个第一个几乎适用于所有允许异步IO的Web服务器)是:

  1. ASP.NET使用为每个传入请求使用不同的线程,因此您可以获得上下文开关的开销
  2. .net不强迫您使用async进行io-bound工作,因此它不像nodejs那样愚蠢,io-bound api呼叫实际上是异步(带有回调)
  3. .net'"等待-Async"添加了编译时间的步骤,以添加"回调",因此您可以编写线性代码(无回调函数传递),与Nodejs
  4. 相比

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

nodejs和.net中的异步之间的差异是使用用户代码的先发制多任务处理。.NET对用户代码使用先发制性多任务处理,而Nodejs则不会。

nodejs使用一个内部线程池来服务IO请求,以及一个用于执行JS代码的线程,包括IO回调。

使用先发制性多任务处理(.NET)的后果之一是,在执行堆栈时,可以通过另一堆执行来更改共享状态。在nodejs中不是这种情况 - 异步操作中没有回调可以与当前执行的堆栈同时运行。JavaScript中不存在另一堆执行。仅当当前执行堆栈完全退出时,异步操作的结果才能用于回调。这样做,简单的 while(true);悬挂了nodejs,因为在这种情况下,当前堆栈不会退出,而下一个循环永远不会启动。

要理解差异考虑两个示例,一个用于js一个。 var p = new Promise(function(resolve){settimeout(Resolve,500," My content");}); p.then(函数(value){//... value ==="我的内容"

在此代码中,您可以在"启动"异步操作后安全地放置一个处理程序(然后),因为您可以确定,没有异步操作发起的回电代码将永远执行直到整个当前呼叫堆栈退出。回调是在下一个周期中处理的。至于计时器回调,它们被对待相同。异步计时器事件JUSS将回调处理在以下周期中进行处理。

在.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代码,可以在单线线程上演示异步处理,并将螺纹池用于异步IO,就像Node一样。(.net包括异步IO操作的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>();
}

最新更新