Тъй като JavaScript е еднопоточен, как уеб работниците в HTML5 извършват многопоточност?

Четох за уеб работници в HTML5, но знам, че JavaScript е еднонишков.

Въпросът ми е:

Как тогава уеб работниците извършват многопоточна работа? или как го симулират, ако не е наистина многонишков? Тук не ми изглежда ясно.


person James Drinkard    schedule 14.03.2012    source източник
comment
Работниците наистина се изпълняват в отделни нишки.   -  person kirilloid    schedule 14.03.2012
comment
Работните нишки са по дефиниция отделни нишки.   -  person Ates Goral    schedule 14.03.2012
comment
Не се обиждам, тук съм, за да уча и помагам. Осъзнавам, че не знам всичко.   -  person James Drinkard    schedule 14.03.2012


Отговори (5)


Както няколко коментара вече посочиха, Workers наистина са многонишкови.

Някои точки, които могат да ви помогнат да изясните мислите си:

  • JavaScript е език, той не дефинира модел на нишки, не е непременно еднонишков
  • В миналото повечето браузъри са били с една нишка (въпреки че това се променя бързо: IE, Chrome, Firefox) и повечето реализации на JavaScript се срещат в браузъри
  • Web Workers не са част от JavaScript, те са функция на браузър, която може да бъде достъпна чрез JavaScript
person robertc    schedule 14.03.2012
comment
Това е мястото, където ми липсваше разликата, тя е със спецификацията на браузъра, а не с езика на JavaScript. - person James Drinkard; 14.03.2012
comment
@JamesDrinkard Мисля, че основният проблем е, че DOM не може лесно да бъде направен многонишков , а JavaScript обикновено се използва за манипулиране на DOM. Но DOM не е JavaScript. - person robertc; 14.03.2012
comment
@JamesDrinkard javascript все още е с една нишка, дори и с уеб работници. Уеб работниците не правят javascript многонишков по никакъв начин, който не е бил преди, помислете за това по следния начин: вие по същество стартирате друг еднонишков процес и комуникирате с него, както бихте могли във възел. js например. JavaScript в браузъра е еднонишков, а javascript в работния е еднонишков, но те могат да комуникират помежду си чрез тънък канал. - person TKoL; 15.03.2018
comment
ето как разбрах: браузърът използва една нишка (която има javascript код), за да рендира DOM и да обработва свързан цикъл на събитията (който също може да съдържа javascript код, за да прави неща, които не са dom, като добавяне на две числа), но можем да използваме worker, през който браузър може да прави само не-dom (все още javascript) код. След това можем да синхронизираме данни между двете (тук вмъкнете многонишкови концепции). И така, перифразирайки @James Drinkard, браузърът обработва DOM в еднопоточен javascript; все още можем да имаме други javascript теми, които не докосват DOM - person gawkface; 30.10.2018

Малко късно, но току-що си зададох същия въпрос и стигнах до следния отговор:
Javascript в браузърите винаги е еднопоточен и основно последствие е, че „едновременният“ достъп към променливи (основното главоболие на многонишковото програмиране) всъщност не е едновременно; това е вярно с изключение на уебработниците, които всъщност се изпълняват в отделни нишки и едновременният достъп до променливи трябва да се третира по малко ясен начин.

Аз не съм JavaScript нинджа, но аз също бях убеден, че JavaScript в браузъра се предоставя като процес с една нишка, без да обръщам много внимание на това дали е вярно или на обосновката зад това убеждение.
Прост факт, който подкрепя това предположението е, че когато програмирате в JavaScript, не трябва да се интересувате от паралелен достъп до споделени променливи. Всеки разработчик, без дори да мисли за проблема, пише код, сякаш всеки достъп до променлива е последователен.
С други думи, не е нужно да се притеснявате за така наречения Модел на памет.

Всъщност няма нужда да разглеждате WebWorkers, за да включите паралелна обработка в JavaScript. Помислете за (асинхронна) AJAX заявка. И помислете колко небрежно бихте се справили с едновременния достъп до променливи:

var counter = 0;

function asyncAddCounter() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4) {
      counter++;
    }
  };
  xhttp.open("GET", "/a/remote/resource", true);
  xhttp.send();
}

asyncAddCounter();
counter++;

Каква е стойността на counter в края на процеса? Това е 2. Няма значение, че се чете и пише „едновременно“, никога няма да доведе до 1. Това означава, че достъпът до counter винаги е последователен. Ако две нишки наистина имат достъп до стойността едновременно, и двете могат да започнат с четене на 0 и двете да напишат 1 накрая.

В браузърите действителното извличане на данни от отдалечен ресурс е скрито за разработчика и вътрешната му работа е извън обхвата на API на JavaScript (това, което браузърът ви позволява да контролирате по отношение на инструкциите на JavaScript). Що се отнася до програмиста, резултатът от мрежовата заявка се обработва от основната нишка.
Накратко, действителното изпълнение на заявката не е видимо, но извикването на обратното извикване (обработване на резултата чрез персонализиран JavaScript код) се изпълнява от главната нишка.
Вероятно, ако не беше за уебработниците, терминът „многопоточност“ никога няма да влезе в света на Javascript.

Изпълнението на заявката и асинхронното извикване на обратното извикване всъщност се постига чрез използване на цикли на събития, а не многопоточност. Това е вярно за няколко браузъра и очевидно за Node.js. Следват някои препратки, в някои случаи малко остарели, но предполагам, че основната идея се запазва и днес.

Този факт е причината, поради която се казва, че JavaScript е управляван от събития, но не и многонишков.< br> Забележете, че по този начин JavaScript позволява асинхронни идиоми, но не и паралелно изпълнение на JavaScript код (извън уебработници). Терминът асинхронен просто обозначава факта, че резултатът от две инструкции може да бъде обработен в разбъркан ред.

Що се отнася до WebWorkers, те са API на JavaScript, които дават на разработчиците контрол над многонишков процес.
Като такива те предоставят изрични начини за обработка на едновременен достъп до споделена памет (четене и запис на стойности в различни нишки ), и това се прави, между другото, по следните начини:

  • изпращате данни към уеб работник (което означава, че новата нишка чете данни) чрез структуриран клонинг: Алгоритъмът за структурирано клониране - Уеб API | MDN. По същество няма "споделена" променлива, вместо това новата нишка получава ново копие на обекта.
  • изпращате данни към уеб работник, като прехвърляте собствеността върху стойността: Transferable - Web API | MDN. Това означава, че само една нишка може да прочете стойността си по всяко време.
  • що се отнася до резултатите, върнати от уеб работниците (как те "пишат"), основната нишка има достъп до резултатите, когато бъде подканена да го направи (например с инструкцията thisWorker.onmessage = function(e) {console.log('Message ' + e.data + ' received from worker');}). Предполагам, че трябва да е чрез обичайния цикъл на събитията.
  • главната нишка и уеб работникът имат достъп до наистина споделена памет, SharedArrayBuffer, която е достъпна за безопасен поток чрез функциите Atomic. Намерих това ясно изложено в тази статия: JavaScript: От работници към споделена памет
  • забележка: работещите в мрежата нямат достъп до DOM, който наистина е споделен!
person Antonio    schedule 23.11.2017

Създавате .js файл като "работник" и той изпълнява процеси в отделна нишка. Можете да предавате JSON данни напред и назад между него и "главната" нишка. Работниците обаче нямат достъп до определени неща като DOM.

Така че, ако, да речем, искате да решите сложни математически задачи, можете да позволите на потребителя да въвежда неща в браузъра, да прехвърли тези променливи на работника, да го оставите да направи изчисленията във фонов режим, докато в главната нишка оставяте потребителя да направи други неща, или да покаже лента за напредъка или нещо подобно, и след това, когато воркърът свърши, той връща отговора обратно и вие го отпечатвате на страницата. Можете дори да решите множество задачи асинхронно и да върнете обратно отговорите в нередовен ред, когато завършат. Доста спретнат!

person JKing    schedule 14.03.2012
comment
JSON (Javascript Object Notation) се съхранява в низове, така че трябва да кажете, че можете да прехвърляте низове. Според този въпрос postMessage може да изпраща клонинги на различни обекти: stackoverflow.com/questions/13761968/ Според статията в MDN (която не споменава, че само низовете са нещо), можете да прехвърляте определени обекти (което е по-бързо от копирането): developer.mozilla.org/en-US/docs/Web/API/Worker /postMessage Въз основа на това би трябвало да е възможно да свържете Workers заедно в конвейер с помощта на MessagePorts... - person Chinoto Vokro; 15.11.2016

Браузърът стартира нишка с javascript, който искате да изпълните. Така че това е истинска нишка, с това нещо за уеб работници вашият js вече не е еднопоточен.

person rapadura    schedule 14.03.2012

Всъщност основното объркване, мисля тук, идва от това, че хората намират хитри начини да правят нещата едновременно. Ако се замислите, JavaScript очевидно не е многонишков и въпреки това имаме начини да правим нещата паралелно, така че какво се случва?

Задаването на правилния въпрос е това, което ще доведе до отговора тук. Кой отговаря за нишките? Има един отговор по-горе, който казва, че JS е просто език, а не модел на нишки. Напълно вярно! JavaScript няма нищо общо с това. Отговорността пада върху V8. Вижте тази връзка за повече информация -› https://v8.dev/ Така че V8 позволява една нишка на JS Контекст, което означава, че колкото и да се опитвате, създаването на нова тема е просто невъзможно. И все пак хората създават така наречените работници и ние се объркваме. За да ми отговорите, ви питам следното. Възможно ли е да стартирате 2 V8 и двата да интерпретират някакъв JS код? Точно решението на нашия проблем. Работниците комуникират със съобщения, защото техният контекст е различен. Те са други неща, които не знаят нищо за нашия контекст, следователно се нуждаят от информация, която идва под формата на съобщение.

person Ivailo Manolov    schedule 28.05.2021