Dlaczego JavaScript nie obsługuje wielowątkowości?

269

Czy jest to celowa decyzja projektowa czy problem z naszymi przeglądarkami na dzień dzisiejszy, który zostanie naprawiony w nadchodzących wersjach?

Niyaz
źródło
3
Zobacz także odpowiedzi na pytanie JavaScript i wątki, aby uzyskać informacje na temat robotów internetowych / wątków roboczych.
Sam Hasler,
115
Witaj, koledze Googler. Możesz zauważyć, że wszystko tutaj wydaje się być dość przestarzałe (zwróć uwagę, że pytanie zostało zadane ponad 5 lat temu). Od czasu zadania, przeglądarki internetowe zyskały pewne możliwości, które, o ile wiem, są mniej więcej wielowątkowe. Spójrz na Web Workers: msdn.microsoft.com/en-us/hh549259.aspx
ArtOfWarfare
2
Multithread.js otacza Web Workers i pozwala na łatwą wielowątkowość w JS. Działa na wszystkich nowych przeglądarkach, w tym iOS Safari. :)
kwh
1
Możliwy duplikat JavaScript i wątków
Matt

Odpowiedzi:

194

JavaScript nie obsługuje wielowątkowości, ponieważ interpreter JavaScript w przeglądarce jest jednym wątkiem (AFAIK). Nawet Google Chrome nie pozwala na równoczesne działanie kodu JavaScript pojedynczej strony internetowej, ponieważ spowodowałoby to poważne problemy z współbieżnością na istniejących stronach internetowych. Wszystko, co robi Chrome, to oddzielne wiele komponentów (różne karty, wtyczki itp.) W osobne procesy, ale nie wyobrażam sobie, żeby jedna strona miała więcej niż jeden wątek JavaScript.

Możesz jednak użyć, jak sugerowano, setTimeoutaby zezwolić na pewnego rodzaju planowanie i „fałszywą” współbieżność. Powoduje to, że przeglądarka odzyskuje kontrolę nad wątkiem renderującym i uruchamia dostarczony kod JavaScript setTimeoutpo upływie określonej liczby milisekund. Jest to bardzo przydatne, jeśli chcesz umożliwić odświeżanie okienka ekranu (tego, co widzisz) podczas wykonywania na nim operacji. Samo zapętlenie np. Współrzędnych i odpowiednia aktualizacja elementu pozwoli ci zobaczyć pozycje początkową i końcową, i nic pomiędzy.

W JavaScript używamy biblioteki abstrakcji, która pozwala nam tworzyć procesy i wątki, którymi zarządza ten sam interpreter JavaScript. To pozwala nam uruchamiać działania w następujący sposób:

  • Proces A, wątek 1
  • Proces A, wątek 2
  • Proces B, wątek 1
  • Proces A, wątek 3
  • Proces A, wątek 4
  • Proces B, wątek 2
  • Wstrzymaj proces A
  • Proces B, wątek 3
  • Proces B, wątek 4
  • Proces B, wątek 5
  • Rozpocznij proces A
  • Proces A, wątek 5

Pozwala to na pewną formę planowania i podobieństwa równoległości, uruchamiania i zatrzymywania wątków itp., Ale nie będzie to prawdziwa wielowątkowość. Nie sądzę, aby kiedykolwiek został zaimplementowany w samym języku, ponieważ prawdziwa wielowątkowość jest przydatna tylko wtedy, gdy przeglądarka może uruchomić wielowątkową stronę (lub nawet więcej niż jeden rdzeń), a trudności są znacznie większe niż dodatkowe możliwości.

Jeśli chodzi o przyszłość JavaScript, sprawdź to: https://developer.mozilla.org/presentations/xtech2006/javascript/

Kamiel Wanrooij
źródło
73
Myślę, że nigdy nie wdrożony jest zbyt wąską wizją. Gwarantuję, że aplikacje sieciowe będą w końcu mogły być naprawdę wielowątkowe (jest to logiczne, ponieważ aplikacje internetowe stają się bardziej dominujące, a sprzęt staje się bardziej równoległy), i jak widzę, ponieważ JavaScript jest de facto językiem programowania stron internetowych, w końcu będzie musiał obsługiwać wielowątkowość lub zostać zastąpiony przez coś, co działa.
devios1
6
Nigdy nie jest to chyba zbyt odważne stwierdzenie :), ale nadal uważam, że zalety prawdziwego wielowątkowego javascript nie są wykonalne w dającej się przewidzieć przyszłości;)
Kamiel Wanrooij
5
Chociaż twierdzę, że pracownicy sieci są bardziej współbieżni poprzez model procesu niż model wątku. Pracownicy sieci wykorzystują przekazywanie wiadomości jako środek komunikacji, który jest eleganckim rozwiązaniem typowych problemów z współbieżnością w aplikacjach wielowątkowych. Nie jestem pewien, czy mogą one jednocześnie obsługiwać te same obiekty, co strona główna. O ile mi wiadomo, nie mogą uzyskać dostępu do DOM. Większość z nich to semantyka, pracownicy sieci wyglądają obiecująco pod każdym względem.
Kamiel Wanrooij
trudności są znacznie większe niż dodatkowe możliwości. Nie jestem pewien, czy pomyślisz o wszystkich dodatkowych możliwościach. Szczególnie myślę o przypadkach, w których webgl jest używany, jak w grach lub wizualizacjach graficznych. Np. Rozważ nową wersję 3D Map Google. W miastach z wieloma modelami 3D mój komputer potrzebuje ~ 2 min, aby załadować wszystko, gdy trzeba wyrenderować wiele domów. Pod pewnymi kątami ani moja karta graficzna, ani moja sieć nie działają na pełnych obrotach. Ale 1 z 8 procesorów ma 100% mocy. Wielowątkowość jest również dużym problemem pod względem liczby klatek na sekundę, jak pokazuje ten przykład: youtube.com/watch?v=sJ2p982cZFc
Scindix
25

JavaScript wielowątkowość (z pewnymi ograniczeniami) jest tutaj. Google zaimplementował pracowników dla Gears, a pracownicy są dołączani do HTML5. Większość przeglądarek już dodała obsługę tej funkcji.

Bezpieczeństwo wątków danych jest gwarantowane, ponieważ wszystkie dane przekazywane do / od pracownika są serializowane / kopiowane.

Aby uzyskać więcej informacji, przeczytaj:

http://www.whatwg.org/specs/web-workers/current-work/

http://ejohn.org/blog/web-workers/

Neil
źródło
8
Ale czy nie jest to bardziej podejście wieloprocesowe niż wielowątkowe? Wątki są znane z działania w obrębie jednej sterty.
beefeather
1
@beefeather, to prawda. To bardziej podejście procesowe.
Neil
23

Tradycyjnie JS był przeznaczony do krótkich, szybko działających fragmentów kodu. Jeśli miałeś poważne obliczenia, zrobiłeś to na serwerze - pomysł aplikacji JS + HTML, która działała w przeglądarce przez długi czas, robiąc rzeczy niebanalne, był absurdalny.

Oczywiście teraz to mamy. Ale przeglądarka zajmie trochę czasu - większość z nich została zaprojektowana w oparciu o model jednowątkowy, a zmiana nie jest łatwa. Google Gears omija wiele potencjalnych problemów, wymagając, aby wykonanie w tle było izolowane - bez zmiany DOM (ponieważ nie jest to bezpieczne dla wątków), bez dostępu do obiektów utworzonych przez główny wątek (to samo). Chociaż jest to restrykcyjne, będzie to prawdopodobnie najbardziej praktyczny projekt w najbliższej przyszłości, zarówno dlatego, że upraszcza projektowanie przeglądarki, jak i ponieważ zmniejsza ryzyko związane z umożliwieniem niedoświadczonym programistom JS bałagania się z wątkami ...

@marcio :

Dlaczego jest to powód, aby nie wdrażać wielowątkowości w JavaScript? Programiści mogą robić, co chcą, korzystając z posiadanych narzędzi.

Więc nie dawajmy im narzędzi, które są tak łatwe do niewłaściwego użycia, że każda inna strona, którą otwieram, powoduje awarię mojej przeglądarki. Naiwna implementacja tego przyniosłaby cię prosto na terytorium, które spowodowało wiele bólów głowy podczas rozwoju IE7: autorzy dodatków grali szybko i luźno z modelem wątków, powodując ukryte błędy, które stały się widoczne, gdy cykle życia obiektu zmieniły się w głównym wątku . ZŁY. Jeśli piszesz wielowątkowe dodatki ActiveX dla IE, myślę, że pochodzi z terytorium; nie znaczy, że musi iść dalej.

Shog9
źródło
6
„zmniejsza to ryzyko związane z> niedozwolonymi programistami JS> bałagan z wątkami” Dlaczego to jest powód, dla którego nie wprowadzono wielowątkowości w JavaScript? Programiści mogą robić, co chcą, korzystając z posiadanych narzędzi. Jeśli jest to dobre lub złe, to ich problem. Dzięki modelowi procesów Google Chrome nie ma nawet wpływu na inne aplikacje. :)
Marcio Aguiar
3
@ Shog9 - „Nie dajmy [programistom] narzędzi, które są tak łatwe do niewłaściwego użycia, że ​​każda inna strona, którą otwieram, powoduje awarię mojej przeglądarki”. - Co? Zgodnie z tą samą logiką żaden język nie powinien mieć wielowątkowości, ponieważ jeśli zaoferują, że każdy inny program, który spróbujesz otworzyć, ulegnie awarii. Tyle że to nie działa w ten sposób. Wątki istnieją w większości języków i większość początkujących programistów ich nie dotyka, a większość z tych, którzy nie wprowadzają ich do produkcji, oraz aplikacje, które nigdy nie stają się popularne ani szeroko stosowane.
ArtOfWarfare
11

Nie znam uzasadnienia tej decyzji, ale wiem, że możesz symulować niektóre korzyści programowania wielowątkowego za pomocą setTimeout. Możesz złudzić, że wiele procesów robi to w tym samym czasie, chociaż w rzeczywistości wszystko dzieje się w jednym wątku.

Niech twoja funkcja wykona trochę pracy, a następnie wywoła coś takiego:

setTimeout(function () {
    ... do the rest of the work...
}, 0);

I wszelkie inne rzeczy, które należy zrobić (takie jak aktualizacje interfejsu użytkownika, animowane obrazy itp.) Zdarzają się, gdy mają szansę.

pkaeding
źródło
Większość przypadków chciałbym użyć loopwewnątrz, setTimeoutale najwyraźniej to nie działa. Czy zrobiłeś coś takiego lub masz hack? przykładem może być tablica 1000 elementów, spodziewam się użyć dwóch pętli dla dwóch setTimeoutwywołań, tak że pierwsza pętla przechodzi przez element print 0..499, druga pętla przechodzi przez element print 500..999.
benjaminz
Zwykle techniką jest uratowanie stanu i kontynuowanie. Na przykład powiedz, że chcesz wydrukować od 0 do 1000, możesz wydrukować od 0 do 499, a następnie wykonać sztuczkę setTimeout z argumentem 500. Kod w środku wiedziałby, że bierze argument (500) i rozpoczyna pętlę od tego miejsca.
Eyal
8

Czy masz na myśli, dlaczego język nie obsługuje wielowątkowości lub dlaczego silniki JavaScript w przeglądarkach nie obsługują wielowątkowości?

Odpowiedź na pierwsze pytanie jest taka, że ​​JavaScript w przeglądarce ma być uruchamiany w piaskownicy oraz w sposób niezależny od maszyny / systemu operacyjnego, dodanie obsługi wielowątkowości skomplikowałoby język i zbytnio wiązało język z systemem operacyjnym.

matowy b
źródło
6

Node.js 10.5+ obsługuje wątki robocze jako funkcję eksperymentalną (można go używać z włączoną opcją --experimental-worker ): https://nodejs.org/api/worker_threads.html

Tak więc reguła jest następująca:

  • jeśli potrzebujesz wykonać operacje związane z We / Wy , użyj wewnętrznego mechanizmu (inaczej callback / promise / async-await)
  • jeśli chcesz wykonać operacje związane z procesorem , użyj wątków roboczych.

Wątki robocze mają być wątkami długowiecznymi, co oznacza, że ​​odradzasz wątek tła, a następnie komunikujesz się z nim poprzez przekazywanie wiadomości.

W przeciwnym razie, jeśli chcesz wykonać duże obciążenie procesora za pomocą anonimowej funkcji, możesz przejść do https://github.com/wilk/microjob , niewielkiej biblioteki zbudowanej wokół wątków roboczych.

Wilk
źródło
4

Tak jak powiedział Matt B, pytanie nie jest bardzo jasne. Zakładając, że pytasz o obsługę wielowątkowości w języku: ponieważ nie jest ona potrzebna dla 99,999% aplikacji działających obecnie w przeglądarce. Jeśli naprawdę tego potrzebujesz, istnieją obejścia (na przykład użycie window.setTimeout).

Ogólnie rzecz biorąc, wielowątkowość jest bardzo, bardzo, bardzo, bardzo, bardzo, bardzo trudna (czy powiedziałem, że jest to trudne?), Jeśli nie wprowadzisz dodatkowych ograniczeń (takich jak używanie tylko niezmiennych danych).

Szara Pantera
źródło
3

Intel przeprowadził pewne badania open source dotyczące wielowątkowości w Javascripcie, które niedawno zaprezentowano na GDC 2012. Oto link do filmu . Grupa badawcza wykorzystała OpenCL, który koncentruje się głównie na zestawach układów Intel i systemie operacyjnym Windows. Projekt nosi nazwę RiverTrail, a kod jest dostępny na GitHub

Niektóre bardziej przydatne linki:

Budowa autostrady obliczeniowej dla aplikacji internetowych

Rohit Reddy Korrapolu
źródło
1

To implementacje, które nie obsługują wielowątkowości. Obecnie Google Gears zapewnia sposób korzystania z pewnej formy współbieżności poprzez wykonywanie zewnętrznych procesów, ale o to chodzi.

Nowa przeglądarka, którą Google ma dziś wypuścić (Google Chrome), wykonuje równolegle jakiś kod, oddzielając go w procesie.

Język podstawowy może oczywiście mieć taką samą obsługę jak, powiedzmy Java, ale obsługa czegoś takiego jak współbieżność Erlanga nie jest nigdzie w pobliżu.

Greg Roberts
źródło
1

JavaScript jest językiem jednowątkowym. Oznacza to, że ma jeden stos wywołań i jeden stos pamięci. Zgodnie z oczekiwaniami wykonuje kod w kolejności i musi zakończyć wykonywanie kodu części przed przejściem do następnego. Jest synchroniczny, ale czasami może być szkodliwy. Na przykład, jeśli funkcja wymaga czasu na wykonanie lub musi na coś poczekać, w międzyczasie zawiesza wszystko.

Omar Bakhsh
źródło
0

O ile słyszałem, Google Chrome będzie miał wielowątkowy javascript, więc jest to problem „bieżących implementacji”.

BlaM
źródło
0

Bez odpowiedniego wsparcia językowego do synchronizacji wątków nawet nowe implementacje nie mają sensu. Istniejące złożone aplikacje JS (np. Wszystko korzystające z ExtJS) najprawdopodobniej uległyby awarii nieoczekiwanie, ale bez synchronizedsłowa kluczowego lub czegoś podobnego bardzo trudno byłoby nawet napisać nowe programy, które zachowują się poprawnie.

Erich Kitzmueller
źródło
-1

Możesz jednak użyć funkcji eval, aby wprowadzić współbieżność W NIEKTÓRY ZAKRES

/* content of the threads to be run */
var threads = [
        [
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');",
            "document.write('Foo <br/>');"
        ],
        [
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');",
            "document.write('Bar <br/>');"
        ]
    ];

window.onload = function() {
    var lines = 0, quantum = 3, max = 0;

    /* get the longer thread length */
    for(var i=0; i<threads.length; i++) {
        if(max < threads[i].length) {
            max = threads[i].length;
        }
    }

    /* execute them */
    while(lines < max) {
        for(var i=0; i<threads.length; i++) {
            for(var j = lines; j < threads[i].length && j < (lines + quantum); j++) {
                eval(threads[i][j]);
            }
        }
        lines += quantum;
    }
}
Madhusoodan P.
źródło
-2

Wielowątkowość z javascript jest oczywiście możliwa przy użyciu webworkerów wprowadzonych przez HTML5.

Główną różnicą między pracownikami sieci a standardowym środowiskiem wielowątkowym jest to, że zasoby pamięci nie są współużytkowane z głównym wątkiem, odniesienie do obiektu nie jest widoczne z jednego wątku do drugiego. Wątki komunikują się poprzez wymianę komunikatów, dlatego możliwe jest wdrożenie algorytmu synchronizacji i współbieżnego wywołania metody zgodnie ze wzorcem projektowym sterowanym zdarzeniami.

Istnieje wiele struktur umożliwiających strukturę programowania między wątkami, w tym OODK-JS, platforma OOP js wspierająca programowanie współbieżne https://github.com/GOMServices/oodk-js-oop-for-js

OBDM
źródło
5
Udostępnianie pamięci to dokładna definicja wątku przeciwnego do osobnego procesu (np. Fork () vs exec ()). Wątki mogą współdzielić obiekty, procesy muszą korzystać z IPC. Pracownicy sieci nie obsługują wielowątkowości.
felixfbecker