Jakie są wady tworzenia wielowątkowej implementacji środowiska wykonawczego JavaScript? [Zamknięte]

51

Przez ostatni tydzień pracowałem nad wielowątkową implementacją środowiska wykonawczego JavaScript. Mam dowód koncepcji wykonany w C ++ przy użyciu JavaScriptCore i boost.

Architektura jest prosta: gdy środowisko wykonawcze zakończy ocenę skryptu głównego, uruchamia się i dołącza do puli wątków, która rozpoczyna pobieranie zadań ze wspólnej kolejki priorytetowej, jeśli dwa zadania próbują jednocześnie uzyskać dostęp do zmiennej, zostaje oznaczona jako atomowa i walczą o dostęp .

Działający wielowątkowy środowisko uruchomieniowe node.js

Problem polega na tym, że kiedy pokazuję ten projekt programistom JavaScript, otrzymuję bardzo negatywne opinie i nie mam pojęcia, dlaczego. Nawet prywatnie wszyscy mówią, że JavaScript ma być jednowątkowy, że istniejące biblioteki będą musiały zostać przepisane, a gremliny odrodzą się i zjadają każdą żywą istotę, jeśli będę dalej nad tym pracował.

Początkowo miałem też natywną implementację coroutine (wykorzystującą konteksty doładowania), ale musiałem to porzucić (JavaScriptCore ma pedantyczny stosunek do stosu), i nie chciałem ryzykować ich gniewu, więc postanowiłem o tym nie wspominać.

Co myślisz? Czy JavaScript ma być jednowątkowy i czy należy go zostawić w spokoju? Dlaczego wszyscy są przeciwni idei jednoczesnego uruchamiania środowiska JavaScript?

Edycja: Projekt jest teraz na GitHub , eksperymentuj z nim sam i daj mi znać, co myślisz.

Poniżej znajduje się obraz obietnic działających na wszystkich rdzeniach procesora równolegle bez rywalizacji:

Bieganie obietnic jednocześnie.

voodooattack
źródło
7
To wydaje się być wysoce opiniotwórczym pytaniem. Czy zapytałeś ludzi, którzy najwyraźniej nie lubili twojego pomysłu, dlaczego uważają, że będzie to kłopotliwe?
5gon12eder
26
Dodanie wątków do czegoś, co nie jest przeznaczone do wielowątkowości, jest jak przekształcenie jednopasmowej drogi w drogę ekspresową bez dostarczania edycji przez kierowcę. Przez większość czasu będzie działał całkiem dobrze, dopóki ludzie nie zaczną losowo upaść. Dzięki wielowątkowości albo będziesz mieć subtelne błędy czasowe, których nie będziesz w stanie odtworzyć, albo nieregularne zachowanie przez większość czasu. Trzeba to projektować. Potrzebujesz synchronizacji wątków. Samo tworzenie atomowych zmiennych nie eliminuje warunków wyścigu.
mgw854
2
Jak zamierzasz obsługiwać wielowątkowy dostęp do stanu wspólnego? „Oznaczony jako atomowy i walcz o dostęp” nie wyjaśnia, w jaki sposób, twoim zdaniem, to naprawdę zadziałałoby. Sądzę, że negatywne nastawienie do tego pomysłu wynika z tego, że ludzie nie mają pojęcia, w jaki sposób sprawiłbyś, by to zadziałało. Lub, jeśli nakładasz cały ciężar na programistę, takiego jak Java lub C ++, na stosowanie odpowiednich muteksów i tak dalej, ludzie prawdopodobnie zastanawiają się, dlaczego chcą tego powikłania i ryzyka programowania w środowisku wolnym od niego.
jfriend00
17
Ponieważ automatyczna koordynacja losowego stanu między wątkami jest uważana za prawie niemożliwy problem, więc nie masz wiarygodności, że możesz zaoferować wszystko, co robi to automatycznie. A jeśli zamierzasz po prostu obciążyć programistę tak, jak robią to Java lub C ++, to większość programistów node.js nie chce tego obciążenia - lubią, że node.js nie musi sobie z tym poradzić Największa część. Jeśli chcesz bardziej współczującego ucha, będziesz musiał wyjaśnić / pokazać, jak i co byś zaoferował w tym względzie oraz dlaczego byłoby to dobre i użyteczne.
jfriend00
3
Kontynuuj swoją pracę. Języki bez wielowątkowości uważam za języki zabawkowe. Myślę, że większość programistów JavaScript pracuje z przeglądarką, która ma model z jednym wątkiem.
Chloe,

Odpowiedzi:

70

1) Wielowątkowość jest niezwykle trudna i niestety sposób, w jaki przedstawiłeś ten pomysł do tej pory, oznacza, że ​​poważnie nie doceniasz jej trudności.

W tej chwili wygląda na to, że po prostu „dodajesz wątki” do języka i martwisz się, jak poprawić go i poprawić. W szczególności:

jeśli dwa zadania próbują jednocześnie uzyskać dostęp do zmiennej, zostaje ona oznaczona jako atomowa i walczą o dostęp.
...
Zgadzam się, że zmienne atomowe nie rozwiążą wszystkiego, ale moim kolejnym celem jest praca nad rozwiązaniem problemu synchronizacji.

Dodanie wątków do Javascript bez „rozwiązania problemu synchronizacji” byłoby jak dodanie liczb całkowitych do Javascript bez „rozwiązania problemu dodawania”. Jest to tak fundamentalne dla natury problemu, że w zasadzie nie ma nawet sensu dyskutować, czy wielowątkowość warto dodać bez konkretnego rozwiązania, bez względu na to, jak bardzo byśmy tego chcieli.

Co więcej, przekształcanie atomów w wszystkie zmienne to coś, co może sprawić, że program wielowątkowy będzie działał gorzej niż jego jednorzędowy odpowiednik, co sprawia, że ​​jeszcze ważniejsze jest testowanie wydajności w bardziej realistycznych programach i sprawdzanie, czy coś zyskujesz, czy nie.

Nie jest też dla mnie jasne, czy próbujesz ukryć wątki przed programistą node.js, czy planujesz je w pewnym momencie ujawnić, tworząc nowy dialekt JavaScript dla programowania wielowątkowego. Obie opcje są potencjalnie interesujące, ale wygląda na to, że jeszcze nie zdecydowałeś, na którą celujesz.

W tej chwili prosi się programistów o rozważenie przejścia ze środowiska jedno-wątkowego na zupełnie nowe środowisko wielowątkowe, w którym nie ma rozwiązania problemu z synchronizacją i nie ma dowodów na to, że poprawia ono wydajność w świecie rzeczywistym, i pozornie nie ma planu rozwiązania tych problemów.

Prawdopodobnie dlatego ludzie nie traktują cię poważnie.

2) Prostota i niezawodność pętli pojedynczych zdarzeń jest ogromną zaletą.

Programiści Javascript wiedzą, że język JavaScript jest „bezpieczny” przed warunkami wyścigowymi i innymi wyjątkowo podstępnymi błędami, które nękają wszystkie autentycznie wielowątkowe programy. Fakt, że potrzebują silnych argumentów, aby przekonać ich do rezygnacji z bezpieczeństwa, nie czyni ich zamkniętymi, lecz czyni z nich odpowiedzialnymi.

O ile nie uda ci się w jakiś sposób zachować tego bezpieczeństwa, każdemu, kto zechce przełączyć się na wielowątkowy node.js, prawdopodobnie lepiej będzie przejść na język taki jak Go, zaprojektowany od podstaw dla aplikacji wielowątkowych.

3) JavaScript obsługuje już „wątki w tle” (WebWorkers) i programowanie asynchroniczne bez bezpośredniego udostępniania zarządzania wątkami programiście.

Te funkcje rozwiązują już wiele typowych przypadków użycia, które wpływają na programistów Javascript w prawdziwym świecie, bez rezygnacji z bezpieczeństwa pętli pojedynczych zdarzeń.

Czy masz na myśli jakieś szczególne przypadki użycia, których nie rozwiązują te funkcje i dla których programiści Javascript chcą rozwiązania? Jeśli tak, dobrym pomysłem byłoby zaprezentowanie swojego wielowątkowego node.js w kontekście tego konkretnego przypadku użycia.


PS Co przekonałoby mnie do przejścia na wielowątkową implementację node.js?

Napisz nietrywialny program w Javascript / node.js, który Twoim zdaniem mógłby skorzystać z autentycznej wielowątkowości. Wykonaj testy wydajności tego przykładowego programu w normalnym węźle i węźle wielowątkowym. Pokaż, że Twoja wersja w znacznym stopniu poprawia wydajność, czas reakcji i użycie wielu rdzeni, bez żadnych błędów i niestabilności.

Kiedy to zrobisz, myślę, że zobaczysz ludzi o wiele bardziej zainteresowanych tym pomysłem.

Ixrec
źródło
1
1) Dobra, przyznaję, że odkładam już kwestię synchronizacji. Kiedy mówię, że „dwa zadania się zmierzą”, to nie jest mój projekt, to głównie spostrzeżenie: dl.dropboxusercontent.com/u/27714141/... - Nie jestem pewien, jakie rodzaje czarnoksięstwa wykonuje tutaj JavaScriptCore, ale nie powinno Czy ten ciąg ulegnie uszkodzeniu, jeśli nie jest z natury atomowy? 2) Zdecydowanie się nie zgadzam. Z tego powodu JS jest postrzegany jako język zabawek. 3) Obietnice ES6 byłyby znacznie wydajniejsze, gdyby zostały zaimplementowane przy użyciu harmonogramu puli wątków.
voodooattack
13
@voodooattack „Z tego powodu JS jest postrzegany jako język zabawek”. Nie, to jest powód , dla którego uważasz, że to język zabawek. Miliony ludzi używają JS każdego dnia i są z niego całkowicie zadowoleni, wady i tak dalej. Upewnij się, że rozwiązujesz problem, który ma wystarczająco dużo innych osób, którego nie można lepiej rozwiązać, zmieniając tylko języki.
Chris Hayes,
@ChrisHayes Pytanie brzmi: po co znosić swoje wady, kiedy mogę je naprawić? Czy współbieżność jako funkcja poprawiłaby JavaScript?
voodooattack
1
@voodooattack To jest pytanie. Czy współbieżność jako funkcja poprawiłaby Javascript? Jeśli możesz uzyskać odpowiedź społeczności na to, że to nie jest „nie”, być może coś już robisz. Wydaje się jednak, że pętla zdarzeń i natywna delegacja węzła do wątków roboczych w celu blokowania zdarzeń wystarczają na większość tego, co ludzie muszą zrobić. Myślę, że jeśli ludzie naprawdę potrzebują wielowątkowego Javascript, będą używać robotów JavaScript. Jeśli jednak potrafisz znaleźć sposób, aby robotnicy pracowali z pierwszorzędnymi funkcjami zamiast plików JS, jednak ... to naprawdę możesz się na czymś zainteresować.
lunchmeat317
7
@voodooattack Ludzie, którzy nazywają JavaScript językiem zabawek, nie wiedzą o czym mówią. Czy to jest język do wszystkiego? Oczywiście, że nie, ale odrzucenie go w ten sposób jest z pewnością błędem. Jeśli chcesz rozwiać pogląd, że JS jest językiem zabawek, stwórz w nim nietrywialną, produkcyjną aplikację lub wskaż istniejącą. Dodanie współbieżności i tak nie zmieni zdania tych ludzi.
jpmc26
16

Zgaduję tutaj, aby zademonstrować problem w twoim podejściu. Nie mogę przetestować tego pod kątem rzeczywistej implementacji, ponieważ nigdzie nie ma linku ...

Powiedziałbym, że dzieje się tak, ponieważ niezmienniki nie zawsze są wyrażane przez wartość jednej zmiennej, a „jedna zmienna” nie wystarcza, aby być zakresem blokady w ogólnym przypadku. Wyobraźmy sobie na przykład, że mamy niezmiennik a+b = 0(saldo banku z dwoma kontami). Dwie poniższe funkcje zapewniają, że niezmiennik jest zawsze przechowywany na końcu każdej funkcji (jednostka wykonania w jednowątkowym JS).

function withdraw(v) {
  a -= v;
  b += v;
}
function deposit(v) {
  b -= v;
  a += v;
}

Teraz w wielowątkowym świecie, co się dzieje, gdy dwa wątki wykonania withdrawi depositw tym samym czasie? Dzięki, Murphy ...

(Być może masz kod, który traktuje + = i - = specjalnie, ale to nie pomaga. W pewnym momencie będziesz mieć stan lokalny w funkcji i bez możliwości zablokowania dwóch zmiennych w tym samym czasie niezmiennik zostać naruszonym.)


EDYCJA: Jeśli twój kod jest semantycznie równoważny kodowi Go na https://gist.github.com/thriqon/f94c10a45b7e0bf656781b0f4a07292a , mój komentarz jest poprawny ;-)

Thriqon
źródło
Ten komentarz jest nieistotny, ale filozofowie potrafią blokować wiele obiektów, ale głodują, ponieważ blokują je w niespójnej kolejności.
Dietrich Epp
3
@voodooattack „Właśnie przetestowałem ...” Czy nigdy nie spotkałeś się z niespójną kolejnością wykonywania przy planowaniu wątków? Różni się od uruchomienia do uruchomienia, od maszyny do maszyny. Siedzenie i przeprowadzanie pojedynczego testu (a nawet stu testów!) Bez identyfikacji mechanizmu planowania operacji jest bezużyteczne.
jpmc26
4
@voodooattack Problem polega na tym, że po prostu testowanie współbieżności nie jest przydatne. Musisz być w stanie udowodnić, że niezmiennik się utrzyma, w przeciwnym razie mechanizmowi nigdy nie można ufać w produkcji.
sapi
1
Ale nie dałeś użytkownikowi żadnych narzędzi do „odpowiedzialnego korzystania z systemu”, ponieważ absolutnie nie ma mechanizmu blokującego. Uczynienie wszystkiego atomowym daje złudzenie bezpieczeństwa wątków (i bierzesz uderzenie wydajności wszystkiego, co jest atomowe, nawet gdy nie potrzebujesz dostępu atomowego), ale tak naprawdę nie rozwiązuje większości problemów z współbieżnością, takich jak ten, który daje tutaj Thriqon. W innym przykładzie spróbuj iterować tablicę w jednym wątku, podczas gdy inny wątek dodaje lub usuwa elementy z tablicy. Co do tego, co sprawia, że ​​uważasz, że implementacja silnika Array jest nawet wątkowo bezpieczna?
Zach Lipton,
2
@voodooattack Jeśli więc użytkownicy mogą używać twoich wątków tylko do funkcji bez wspólnych danych lub efektów ubocznych (i lepiej nie będą ich używać do niczego innego, ponieważ, jak widzieliśmy tutaj, nie ma sposobu na zapewnienie bezpieczeństwa wątków), to jaką wartość zapewniasz pracownikom sieci Web (lub jednej z wielu bibliotek, które zapewniają bardziej użyteczny interfejs API wokół pracowników sieci Web)? Pracownicy sieci Web są znacznie bezpieczniejsi, ponieważ uniemożliwiają użytkownikom korzystanie z systemu „nieodpowiedzialnie”.
Zach Lipton,
15

Dziesięć lat temu Brendan Eich (wynalazca JavaScript) napisał esej zatytułowany „ Threads Suck” , który jest zdecydowanie jednym z niewielu kanonicznych dokumentów dotyczących mitologii projektowania JavaScript.

Czy to prawda, to kolejne pytanie, ale myślę, że miało to duży wpływ na to, jak społeczność JavaScript myśli o współbieżności.

Erik Pukinskis
źródło
31
Ostatnią osobą, od której chciałbym uzyskać porady, jest Brendan Eich. Cała jego kariera opiera się na tworzeniu JavaScriptu, co jest tak złe, że stworzyliśmy mnóstwo narzędzi, które próbują obejść jego wrodzoną bzdurę. Pomyśl, ile godzin programistów zostało przez niego zmarnowanych na świecie.
Phil Wright,
12
Chociaż rozumiem, dlaczego ogólnie lekceważysz jego opinię, a nawet twoją pogardę dla JavaScript, nie rozumiem, w jaki sposób Twoja perspektywa pozwoliłaby zignorować jego wiedzę w tej dziedzinie.
Billy Cravens,
4
@BillyCravens haha, nawet kanoniczna książka na temat Javascript: „Javascript the good parts ” Crockforda oddaje grę w tytule. Traktuj postawy Eicha w ten sam sposób, po prostu trzymaj się rzeczy, które według niego są dobre :-)
gbjbaanb 12.04.16
13
@PhilWright: Jego pierwszą implementacją Javascript był wariant Lisp. Co dla mnie zyskuje ogromny szacunek. Decyzja jego szefa, aby zmusić go do zastąpienia składni Lisp składnią podobną do C, nie jest jego winą. JavaScript w jego rdzeniu nadal jest środowiskiem uruchomieniowym Lisp.
slebetman
7
@PhilWright: Nie powinieneś obwiniać Eicha za niesmaczność języka. Ma błędy we wczesnych implementacjach i potrzebę kompatybilności wstecznej dla języka WWW, który uniemożliwił dojrzewanie JS. Podstawowe pojęcia nadal tworzą wspaniały język.
Bergi,
8

Dostęp atomowy nie przekłada się na zachowanie bezpieczne dla wątków.

Jednym z przykładów jest sytuacja, w której globalna struktura danych musi być niepoprawna podczas aktualizacji, takiej jak zmiana skrótu (na przykład podczas dodawania właściwości do obiektu) lub sortowanie tablicy globalnej. W tym czasie nie można zezwolić na dostęp do zmiennej przez inny wątek. Zasadniczo oznacza to, że musisz wykryć całe cykle odczytu-aktualizacji-zapisu i zablokować to. Jeśli aktualizacja nie jest trywialna, spowoduje to zatrzymanie problematycznego terytorium.

JavaScript jest od początku jednowątkowy i piaskowiony, a cały kod jest napisany z uwzględnieniem tych założeń.

Ma to wielką zaletę w odniesieniu do izolowanych kontekstów i pozwala na uruchamianie 2 oddzielnych kontekstów w różnych wątkach. Mam również na myśli, że ludzie piszący javascript nie muszą wiedzieć, jak radzić sobie z warunkami wyścigu i różnymi innymi wielowątkowymi błędami.

maniak zapadkowy
źródło
Dlatego myślę, że interfejs API harmonogramu powinien być bardziej zaawansowany i wewnętrznie wykorzystywany do obietnic i funkcji, które nie mają skutków ubocznych.
voodooattack
6

Czy Twoje podejście znacząco poprawi wydajność?

Wątpliwy. Naprawdę musisz to udowodnić.

Czy Twoje podejście ułatwi / przyspieszy pisanie kodu?

Zdecydowanie nie, kod wielowątkowy jest wielokrotnie trudniejszy do uzyskania niż kod jednowątkowy.

Czy twoje podejście będzie bardziej niezawodne?

Zakleszczenia, warunki wyścigu itp. To koszmar do naprawienia.

Phil Wright
źródło
2
Spróbuj zbudować raytracer za pomocą node.js, teraz spróbuj ponownie z wątkami. Wieloprocesowość to nie wszystko.
voodooattack
8
@voodooattack, nikt przy zdrowych zmysłach nie napisałby ray-tracera używając javascript, z wątkami lub bez, ponieważ jest to stosunkowo prosty, ale wymagający intensywnych obliczeń algorytm, który lepiej napisać w pełni skompilowanym języku, najlepiej z obsługą SIMD . W przypadku problemów, z których korzysta javascript, wieloprocesowy jest wystarczający.
Jan Hudec
@JanHudec: Heh, JS również otrzyma wsparcie SIMD :-) hacks.mozilla.org/2014/10/introducing-simd-js
Bergi
2
@voodooattack Jeśli ich nie znasz, spójrz na SharedArrayBuffers . JavaScript dostaje coraz więcej konstrukcji współbieżnych, ale są one dodawane wyjątkowo ostrożnie, rozwiązując określone problemy, próbując zminimalizować podejmowanie złych decyzji projektowych, z którymi będziemy musieli żyć przez lata.
REINSTATE MONICA -Jeremy Banks
2

Twoja implementacja nie polega tylko na wprowadzeniu współbieżności, ale raczej na wprowadzeniu określonego sposobu implementacji współbieżności, tj. Współbieżności według współdzielonego stanu zmiennego. W ciągu historii ludzie korzystali z tego rodzaju współbieżności, co doprowadziło do wielu problemów. Oczywiście możesz tworzyć proste programy, które doskonale współpracują ze współdzieloną zmienną współbieżnością stanu, ale prawdziwy test dowolnego mechanizmu nie jest tym, co potrafi, ale można go skalować, gdy program się komplikuje, a do programu dodaje się coraz więcej funkcji. Pamiętaj, że oprogramowanie nie jest statyczną rzeczą, którą budujesz raz i po zakończeniu, a raczej ewoluuje w czasie i jeśli jakikolwiek mechanizm lub koncepcja może ”

Możesz spojrzeć na inne modele współbieżności (np. Przekazywanie wiadomości), aby dowiedzieć się, jakie korzyści zapewniają te modele.

Ankur
źródło
1
Myślę, że obietnice ES6 skorzystałyby na modelu mojej implementacji, ponieważ nie walczą o dostęp.
voodooattack
Zobacz specyfikację WebWorkers. Istnieją pakiety npm, które zapewniają ich implementację, ale możesz zaimplementować je jako rdzeń silnika, a nie jako pakiet
Ankur
JavaScriptCore (implementacja pakietu JS, którego używam) już je implementuje, to tylko flaga kompilacji.
voodooattack
Dobrze. Pracownicy sieciowi są współbieżni z przekazywaniem wiadomości. Możesz wypróbować z nimi przykład raytracera i porównać go z podejściem do stanu zmiennego.
Ankur,
4
Przekazywanie wiadomości jest zawsze realizowane na podstawie stanu zmiennego, co oznacza, że ​​będzie wolniejsze. Nie rozumiem tutaj twojego punktu widzenia. : - /
voodooattack
1

To jest potrzebne. Brak mechanizmu niskiego poziomu współbieżności w węźle js ogranicza jego zastosowania w takich dziedzinach, jak matematyka i bioinformatyka itp. Poza tym współbieżność z wątkami niekoniecznie koliduje z domyślnym modelem zgodności stosowanym w węźle. Istnieją dobrze znane semantyki dotyczące wątków w środowisku z główną pętlą zdarzeń, takich jak frameworki interfejsu użytkownika (i nodejs), i które są zdecydowanie zbyt skomplikowane w większości sytuacji, w których nadal mają prawidłowe zastosowania.

Jasne, twoja przeciętna aplikacja internetowa nie będzie wymagała wątków, ale spróbuj zrobić coś nieco mniej konwencjonalnego, a brak prymitywnej współzależności niskiego poziomu szybko porwie cię do czegoś innego, co ją oferuje.

dryajov
źródło
4
Ale „matematyka i bioinformatyka” lepiej byłoby napisać w języku C #, JAVA lub C ++
Ian
W rzeczywistości w tych obszarach dominują języki Python i Perl.
dryajov
1
Właściwie głównym powodem, dla którego to wdrażam, są aplikacje do uczenia maszynowego. Więc masz rację.
voodooattack
@dryajov Ciesz się, że nie wiesz, jak duży jest FORTRAN w niektórych obszarach nauki obliczeniowej ...
cmaster
@dryajov Ponieważ są bardziej dostępne dla ludzi, którzy być może nie są programistami w pełnym wymiarze godzin, nie dlatego, że są z natury lepsi w sekwencjonowaniu genomu - mamy specjalnie opracowane języki, takie jak R, i opracowaliśmy w tym celu naukowe języki, takie jak Fortran.
kot
0

Naprawdę wierzę, że to dlatego, że jest to inny i potężny pomysł. Przeciwstawiasz się systemom przekonań. Rzeczy stają się akceptowane lub popularne przez wpływy sieciowe nie na podstawie zasług. Również nikt nie chce przystosować się do nowego stosu. Ludzie automatycznie odrzucają rzeczy, które są zbyt różne.

Jeśli możesz wymyślić sposób, aby przekształcić go w zwykły moduł npm, który wydaje się mało prawdopodobny, być może niektórzy z niego skorzystają.

Jason Livesay
źródło
Czy masz na myśli to, że programiści JS są zablokowani przez dostawcę na npm?
voodooattack
3
Pytanie dotyczy nowego systemu wykonawczego, a nie jakiegoś modułu npm, a także zmienna współbieżność stanu współdzielonego to naprawdę stary pomysł.
Ankur,
1
@voodooattack Mam na myśli, że są oni zablokowani w podejściu, które jest już popularne i prawie niemożliwe będzie przezwyciężenie uprzedzeń status quo.
Jason Livesay