2014-12-26 8 views
9

В настоящее время я изучаю node.js, и я вижу 2 примера для программы sync и asycn (тот же).Node.js sync vs. async

Я понимаю концепцию обратного вызова, но я пытаюсь понять преимущество второго (асинхронного) примера, так как кажется, что они оба делают то же самое, даже если это различие .. .

Не могли бы вы объяснить причину, почему второй пример будет лучше? Я буду рад получить более широкое объяснение, которое поможет мне понять концепцию.

спасибо!

первый пример:

var fs = require('fs'); 

function calculateByteSize() { 
    var totalBytes = 0, 
     i, 
     filenames, 
     stats; 
    filenames = fs.readdirSync("."); 
    for (i = 0; i < filenames.length; i ++) { 
     stats = fs.statSync("./" + filenames[i]); 
     totalBytes += stats.size; 
    } 
    console.log(totalBytes); 
} 

calculateByteSize(); 

второй пример:

var fs = require('fs'); 

var count = 0, 
    totalBytes = 0; 

function calculateByteSize() { 
    fs.readdir(".", function (err, filenames) { 
     var i; 
     count = filenames.length; 

     for (i = 0; i < filenames.length; i++) { 
      fs.stat("./" + filenames[i], function (err, stats) { 
       totalBytes += stats.size; 
       count--; 
       if (count === 0) { 
        console.log(totalBytes); 
       } 
      }); 
     } 
    }); 
} 

calculateByteSize(); 

ответ

6

Ваш первый пример все блокировки ввода/вывода. Другими словами, вам нужно будет дождаться завершения операции readdir перед прохождением через каждый файл. Затем вам нужно будет заблокировать (ждать) каждую отдельную операцию синхронизации, чтобы выполнить ее, прежде чем переходить к следующему файлу. После завершения calculateByteSize() код не может работать до тех пор, пока все операции не будут завершены.

Асинхронный (второй) пример с другой стороны не является блокировкой с использованием шаблона обратного вызова. Здесь выполнение возвращается сразу после вызова calculateByteSize(), как только вызывается fs.readdir (но до запуска обратного вызова). Когда задача readdir завершена, он выполняет обратный вызов вашей анонимной функции. Здесь он проходит через каждый из файлов и снова выполняет неблокирующие вызовы fs.stat.

Второй вариант более выгоден. Если вы можете притворяться, что вызовы readdir или stat могут варьироваться от 250 мс до 750 мс для завершения (это, вероятно, не так), вы ожидаете последовательных вызовов в ваших операциях синхронизации. Однако операции async не заставят вас ждать между каждым вызовом.Другими словами, перебирая файлы readdir, вам нужно будет дождаться завершения каждой операции stat, если вы делаете это синхронно. Если бы вы сделали это асинхронно, вам не пришлось бы ждать, чтобы вызвать каждый вызов fs.stat.

+2

Спасибо! удивительный ответ. так что, другими словами, во втором примере мы можем получить stat для третьего файла до получения первого файла, верно? – FED

+0

Где можно узнать больше о том, что происходит за кулисами? Как объяснялось в вашем ответе. –

+0

Работа с привязкой к вводу/выводу не требует процессора, поэтому блокировка потока, ожидающего завершения, неэффективна. Javascript использует события/обратные вызовы, когда данные готовы, позволяя текущему потоку использовать ресурсы ЦП. https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/ – Patrick

4

В первом примере, процесс Node.js, который однопоточный, блокирует в течение всего времени Вашего readdirSync , и не может ничего сделать, кроме как ждать возвращения результата. Во втором примере процесс может обрабатывать другие задачи, и цикл событий возвращает его к продолжению обратного вызова, когда результат будет доступен. Таким образом, вы можете обрабатывать гораздо более высокую общую пропускную способность, используя асинхронный код. Время, затрачиваемое на чтение readdir в первом примере, возможно, в тысячи раз больше времени, затрачиваемого на выполнение кода, поэтому вы теряете 99,9% или больше вашего процессорного времени.

2

В вашем примере преимущество асинхронного программирования действительно не так заметно. Но предположим, что ваша программа также должна заниматься другими вещами. Помните, что ваш JavaScript-код работает в одном потоке, поэтому, когда вы выбрали синхронную реализацию, программа не может ничего сделать, кроме как ждать завершения операции ввода-вывода. При использовании программирования асинхронной, ваша программа может выполнять другие важные задачи, в то время как операции ввода-вывода работает в фоновом режиме (вне резьбы JavaScript)

0

Много хороших ответов здесь, но не забудьте также прочитать документы:

Синхронные версии будут блокировать весь процесс до тех пор, пока они не завершатся - остановка всех соединений.

Существует хороший обзор синхронизации против асинхронном в документации: http://nodejs.org/api/fs.html#fs_file_system

1

Не могли бы вы объяснить причину, почему второй пример будет лучше? Я буду рад получить все более широкое объяснение, которое поможет мне понять концепцию.

Это все о параллелизме для сетевых серверов (таким образом, это имя «узел»). Если бы это было в скрипте сборки, второй, синхронный пример был бы «лучше», потому что это более просто. И учитывая один диск, может быть не так много фактической выгоды, чтобы сделать его асинхронным.

Однако в сетевой службе первая синхронная версия блокирует весь процесс и отменяет основной принцип проектирования узла. Производительность будет медленной, так как количество одновременных клиентов увеличилось. Однако второй, асинхронный пример будет работать относительно хорошо, ожидая, пока относительно медленная файловая система вернется с результатами, она может обрабатывать все относительно быстрые операции ЦП одновременно. Асинхронная версия должна в основном иметь возможность насыщать вашу файловую систему, и сколько бы файловая система не могла ее доставить, узел сможет получить ее для клиентов с такой скоростью.