Подтвердить что ты не робот

Node.js vs Async/ожидание в .net

Может ли кто-нибудь объяснить/перенаправить меня, какая разница между Node.js async model (non blocking thread) и любым другим языком, например, С# асинхронным способом обработки ввода-вывода. Мне кажется, что обе модели одинаковы. Пожалуйста, предложите.

4b9b3361

Ответ 1

Обе модели очень похожи. Есть два основных отличия, один из которых скоро уходит (для некоторого определения "скоро" ).

Одно отличие состоит в том, что Node.js асинхронно однопоточен, в то время как ASP.NET асинхронно многопоточен. Это означает, что код Node.js может сделать некоторые упрощающие предположения, потому что весь ваш код всегда работает на одном и том же потоке. Поэтому, когда ваш код ASP.NET await s, он может возобновиться в другом потоке, и это зависит от вас, чтобы избежать таких ситуаций, как поточно-локальное состояние.

Тем не менее, эта же разница также является сильной стороной для ASP.NET, потому что это означает async. ASP.NET может масштабировать из коробки до полных возможностей вашего сервера. Если вы считаете, например, 8-ядерную машину, то ASP.NET может обрабатывать (синхронные части) 8 запросов одновременно. Если вы помещаете Node.js на суппорт-сервер, то он обычно запускает 8 отдельных экземпляров Node.js и добавляет что-то вроде nginx или простой пользовательский балансировщик нагрузки, который обрабатывает запросы маршрутизации для этого сервера. Это также означает, что если вы хотите, чтобы другие ресурсы распределялись по всему серверу (например, кэш), вам также нужно будет перемещать их из-под-proc.

Другим важным отличием является на самом деле разница в языке, а не в платформе. Асинхронная поддержка JavaScript ограничена обратными вызовами и promises, и даже если вы используете лучшие библиотеки, вы все равно получите действительно неудобный код, когда будете делать что-то нетривиальное. Напротив, поддержка async/await в С#/VB позволяет писать очень естественный асинхронный код (и, что более важно, поддерживаемый асинхронный код).

Однако языковая разница уходит. Следующая редакция JavaScript представит генераторы, которые (вместе со вспомогательной библиотекой) сделают асинхронный код в Node.js таким же естественным, как сегодня, используя async/await. Если вы хотите сейчас играть с "скоростями", генераторы были добавлены в V8 3.19, который был перенесен в Node.js 0.11.2 (ветвь Нестабильный). Передайте --harmony или --harmony-generators, чтобы явно включить поддержку генератора.

Ответ 2

Разница между асинхронной моделью Node.js и моделью С# async/await огромна. Асинхронная модель, имеющая Node.js, похожа на асинхронную модель old в С# и .Net, называемую асинхронным шаблоном на основе событий (EAP). С# и .Net имеют 3 асинхронные модели, вы можете прочитать о них в асинхронных шаблонах программирования. Самой современной асинхронной моделью в С# является Task-based с ключевыми словами С# async и await, вы можете прочитать об этом в Task- основанный на асинхронном шаблоне. Слова С# async/ ждут делают асинхронный код линейным и позволяют вам избегать "Callback Hell" намного лучше, чем на любом из других языков программирования. Вам нужно просто попробовать это, и после этого вы никогда не сделаете это иначе. Вы просто пишете код, потребляющий асинхронные операции, и не беспокойтесь о читаемости, потому что похоже, что вы пишете какой-либо другой код. Смотрите видео:

И, пожалуйста, попробуйте сделать что-то асинхронное как в С#, так и в Node.js для сравнения. Вы увидите разницу.

ИЗМЕНИТЬ: Поскольку Node.js V8 JavaScript-движок поддерживает генераторы определенные в проекте ECMAScript 6 Draft, также можно легко избежать "Обратный звонок" в коде JavaScript. Он привносит некоторую форму async/ожидание в JavaScript

Ответ 3

С nodejs все запросы отправляются в очередь событий. Node цикл событий использует один поток для обработки элементов в очереди событий, выполнения всех операций, отличных от IO, и отправки в С++ threadpool (с использованием обратных вызовов javascript для управления асинхронностью) всех операций с привязкой IO. Затем потоки С++ добавляют в очередь событий свои результаты.

Различия с ASP.NET(два первых применяются практически ко всем веб-серверам, которые разрешают асинхронный ввод-вывод):

  • ASP.NET использует поток для каждого входящего запроса, поэтому вы получаете накладные расходы на переключение контекста.
  • .NET не заставляет вас использовать async для работы с IO-привязкой, поэтому он не так идиоматичен, как nodejs, где IO-связанные вызовы api де-факто async (с обратными вызовами)
  • .NET '' await-async 'добавьте шаг во время компиляции, чтобы добавить "обратные вызовы", чтобы вы могли написать линейный код (без функции обратного вызова), в отличие от nodejs

В Интернете так много мест, которые описывают архитектуру Node, но вот что-то: http://johanndutoit.net/presentations/2013/02/gdg-capetown-nodejs-workshop-23-feb-2013/index.html#1

Ответ 4

Разница между async в Nodejs и .NET заключается в использовании превентивной многозадачности для кода пользователя. .NET использует упреждающую многозадачность для кода пользователя, а Nodejs - нет.

Nodejs использует внутренний пул потоков для обслуживания запросов ввода-вывода и один поток для выполнения вашего JS-кода, включая обратные вызовы IO.

Одним из последствий использования превентивной многозадачности (.NET) является то, что разделяемое состояние может быть изменено другим стеком исполнения при выполнении стека. Это не относится к Nodejs - никакой обратный вызов из асинхронной операции не может выполняться одновременно с исполняемым стеке. В Javascript нет других стеков исполнения. Результат операции async будет доступен для обратных вызовов только тогда, когда текущий стек выполнения полностью завершится. При этом простой while(true); зависает Nodejs, потому что в этом случае текущий стек не выходит и следующий цикл никогда не запускается.

Чтобы понять разницу, рассмотрим два примера: один для js - один для сети.   var p = new Promise (функция (разрешить) {setTimeout (разрешение, 500, "мой контент" );});   p.then(function (value) {//... value === "мой контент"

В этом коде вы можете безопасно поместить обработчик (затем) после того, как вы "запустили" операцию async, потому что можете быть уверены, что никакой код обратного вызова, инициированный асинхронной операцией, никогда не будет выполняться до тех пор, пока весь текущий вызов выходы стека. Обратные вызовы обрабатываются в следующих циклах. Что касается обратных вызовов таймера, то они обрабатываются одинаково. Async timer event justs ставит обработку обратного вызова в очередь для обработки в следующем цикле.

В .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, демонстрирующий асинхронную обработку в одном потоке и использование пула потоков для async IO, как это делает node. (.NET включает в себя 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>();
}