Co to jest nieblokujące lub asynchroniczne operacje we / wy w Node.js?

136

W kontekście silników JavaScript po stronie serwera, czym jest nieblokujące we / wy lub asynchroniczne operacje we / wy? Widzę, że wspomina się o tym jako o przewadze nad implementacjami po stronie serwera Java.

Anand
źródło
3
Aby zrozumieć tę koncepcję, warto pomyśleć o tagach skryptów w środowisku przeglądarki. Zakas ma świetny artykuł na ten temat - kilka pierwszych sekcji powinno wystarczyć do wyjaśnienia pojęcia blokowania: nczonline.net/blog/2010/08/10/what-is-a-non-blocking-script
netpoetica

Odpowiedzi:

317

Synchroniczne vs asynchroniczne

Synchroniczne wykonanie zwykle odnosi się do kodu wykonywanego w sekwencji. Wykonywanie asynchroniczne odnosi się do wykonywania, które nie jest uruchamiane w kolejności, w jakiej występuje w kodzie. W poniższym przykładzie operacja synchroniczna powoduje uruchomienie alertów w sekwencji. Podczas operacji asynchronicznej, podczas gdy alert(2)wydaje się być wykonywana jako druga, tak się nie dzieje.

Synchroniczne: 1, 2, 3

alert(1);
alert(2);
alert(3);

Asynchroniczne: 1,3,2

alert(1);
setTimeout(() => alert(2), 0);
alert(3);

Blokowanie vs Nieblokowanie

Blokowanie odnosi się do operacji, które blokują dalsze wykonywanie do zakończenia tej operacji. Nieblokowanie odnosi się do kodu, który nie blokuje wykonania. W podanym przykładzie localStoragejest to operacja blokująca, ponieważ wstrzymuje wykonywanie odczytu. Z drugiej strony fetchjest operacją nieblokującą, ponieważ nie wstrzymuje alert(3)wykonania.

// Blocking: 1,... 2
alert(1);
var value = localStorage.getItem('foo');
alert(2);

// Non-blocking: 1, 3,... 2
alert(1);
fetch('example.com').then(() => alert(2));
alert(3);

Zalety

Jedną z zalet nieblokujących, asynchronicznych operacji jest to, że można zmaksymalizować użycie pojedynczego procesora oraz pamięci.

Synchroniczny, blokujący przykład

Przykładem synchronicznych operacji blokujących jest sposób, w jaki niektóre serwery WWW, takie jak serwery Java lub PHP, obsługują żądania we / wy lub żądania sieciowe. Jeśli twój kod czyta z pliku lub bazy danych, twój kod „blokuje” wykonanie wszystkiego po nim. W tym okresie Twoja maszyna zatrzymuje pamięć i czas przetwarzania dla wątku, który nic nie robi .

Aby zaspokoić inne żądania, gdy ten wątek utknął, zależy od oprogramowania. Większość oprogramowania serwerowego tworzy więcej wątków, aby obsłużyć dodatkowe żądania. Wymaga to większej ilości pamięci i przetwarzania.

Przykład asynchroniczny, nieblokujący

Asynchroniczne, nieblokujące serwery - takie jak te wykonane w Node - używają tylko jednego wątku do obsługi wszystkich żądań. Oznacza to, że wystąpienie Node maksymalnie wykorzystuje pojedynczy wątek. Twórcy zaprojektowali go z założeniem, że wąskim gardłem są operacje we / wy i operacje sieciowe.

Kiedy żądania docierają do serwera, są obsługiwane pojedynczo. Jednak gdy obsługiwany kod musi na przykład zapytać o bazę danych, wysyła wywołanie zwrotne do drugiej kolejki, a główny wątek będzie kontynuował działanie (nie czeka). Teraz, gdy operacja bazy danych zakończy się i powróci, odpowiednie wywołanie zwrotne jest wyciągane z drugiej kolejki i umieszczane w kolejce w trzeciej kolejce, gdzie oczekuje na wykonanie. Kiedy silnik ma szansę wykonać coś innego (np. Gdy stos wykonania jest opróżniany), odbiera wywołanie zwrotne z trzeciej kolejki i wykonuje go.

Józefa
źródło
5
Nie jestem pewien, czy rozumiem Twój drugi akapit w sekcji Blokowanie w PHP . Czy mówisz, że „Chociaż PHP normalnie blokowałoby operacje we / wy, nie dzieje się tak, ponieważ system operacyjny automatycznie wątkuje operacje we / wy.”? A może mówisz, że nie jest to problem w PHP, ponieważ PHP automatycznie tworzy nowy wątek dla każdego żądania, więc jedno zablokowane żądanie nie zatrzymuje całego środowiska PHP? (Domyślam się, że to drugie ..)
dcow
6
To drugie.
Joseph
2
poczekaj, jeśli chodzi o to drugie, jakie są zalety nieblokującego PHP I / O (jak reagujPHP lub coś innego) nad blokującym. nadal mylić
Sunu Pinasthika Fajar
5
@CharlieParker Yes. Operacja asynchroniczna działa równolegle z kodem. Jednak wywołanie zwrotne, które „wraca” do wyników operacji asynchronicznej, jest umieszczane w kolejce do wykonania w kodzie głównym, gdy kod główny nie jest zajęty.
Joseph
2
@CharlieParker Oto post, który zawiera więcej informacji na temat wewnętrznych elementów mechanizmu asynchronicznego.
Joseph
7
var startTime = new Date().getTime();
var getEndTime = () => {
    var tempEndTime = new Date().getTime();
    var second = (tempEndTime - startTime)/1000
    return `took ${second} sec...to finish\n`
}

console.log('1: start App', getEndTime())
setTimeout(()=>{
    console.log('2: setTimeout', getEndTime())
}, 1000)
console.log('3: End App', getEndTime())

// console -> Process Order:  1 -> 3 -> 2

Przykład kodu

Wayne Chiu
źródło