Это преднамеренное дизайнерское решение или проблема современных браузеров, которая будет исправлена в следующих версиях?
Почему JavaScript не поддерживает многопоточность?
Ответы (15)
JavaScript не поддерживает многопоточность, поскольку интерпретатор JavaScript в браузере является однопоточным (AFAIK). Даже Google Chrome не позволяет запускать JavaScript одной веб-страницы одновременно, потому что это вызовет серьезные проблемы параллелизма на существующих веб-страницах. Все, что делает Chrome, - это разделяет несколько компонентов (разные вкладки, плагины и т. Д.) На отдельные процессы, но я не могу представить себе одну страницу, имеющую более одного потока JavaScript.
Однако вы можете использовать, как было предложено, setTimeout
, чтобы разрешить какое-то планирование и «фальшивый» параллелизм. Это заставляет браузер восстановить контроль над потоком рендеринга и запустить код JavaScript, предоставленный setTimeout
, через заданное количество миллисекунд. Это очень полезно, если вы хотите, чтобы область просмотра (то, что вы видите) обновлялась во время выполнения операций с ней. Просто прокручиваю, например. координаты и соответствующее обновление элемента просто позволит вам увидеть начальную и конечную позиции, и ничего между ними.
Мы используем библиотеку абстракций в JavaScript, которая позволяет нам создавать процессы и потоки, которыми управляет один и тот же интерпретатор JavaScript. Это позволяет нам запускать действия следующим образом:
- Процесс A, поток 1
- Процесс A, поток 2
- Процесс B, поток 1
- Процесс A, поток 3
- Процесс A, поток 4
- Процесс B, поток 2
- Приостановить процесс A
- Процесс B, поток 3
- Процесс B, поток 4
- Процесс B, поток 5
- Начать процесс A
- Процесс A, поток 5
Это допускает некоторую форму планирования и имитирует параллелизм, запуск и остановку потоков и т. Д., Но это не будет истинной многопоточностью. Я не думаю, что это когда-либо будет реализовано в самом языке, поскольку настоящая многопоточность полезна только в том случае, если браузер может запускать одностраничный многопоточный (или даже более одного ядра), а трудности там намного больше. чем дополнительные возможности.
Что касается будущего JavaScript, проверьте это: https://web.archive.org/web/20170920070053/https://developer.mozilla.org/presentations/xtech2006/javascript/
Многопоточность JavaScript (с некоторыми ограничениями) здесь. Google внедрил воркеры для Gears, и они включены в HTML5. Большинство браузеров уже добавили поддержку этой функции.
Потоковая безопасность данных гарантируется, потому что все данные, передаваемые работнику / от работника, сериализуются / копируются.
Для получения дополнительной информации прочтите:
http://www.whatwg.org/specs/web-workers/current-work/
http://ejohn.org/blog/web-workers/
Традиционно JS предназначался для коротких, быстро выполняющихся фрагментов кода. Если у вас были большие вычисления, вы делали это на сервере - идея приложения на JS + HTML, которое долгое время работало в вашем браузере и выполняло нетривиальные вещи, была абсурдной.
Конечно, теперь оно у нас есть. Но браузерам потребуется немного времени, чтобы наверстать упущенное - большинство из них были разработаны на основе однопоточной модели, и изменить ее непросто. Google Gears устраняет множество потенциальных проблем, требуя изолированного фонового выполнения - без изменения DOM (поскольку он не является поточно-ориентированным), без доступа к объектам, созданным основным потоком (то же самое). Хотя это и носит ограничительный характер, это, вероятно, будет наиболее практичным дизайном в ближайшем будущем, потому что он упрощает дизайн браузера и потому, что он снижает риск, связанный с тем, что неопытным JS-кодерам разрешается возиться с потоками ...
Почему это причина не реализовывать многопоточность в Javascript? Программисты могут делать все, что захотят, с помощью имеющихся у них инструментов.
Так что давайте не будем давать им инструменты, которыми так легко злоупотребить, что любой другой веб-сайт, который я открываю, приводит к сбою моего браузера. Наивная реализация этого приведет вас прямо на территорию, которая вызвала у MS столько головной боли во время разработки IE7: авторы надстроек играли быстро и свободно с потоковой моделью, что приводило к скрытым ошибкам, которые становились очевидными, когда жизненные циклы объектов изменялись в основном потоке. . ПЛОХОЙ. Если вы пишете многопоточные надстройки ActiveX для IE, я полагаю, что это связано с территорией; не означает, что нужно идти дальше этого.
Я не знаю обоснования этого решения, но знаю, что вы можете смоделировать некоторые преимущества многопоточного программирования с помощью setTimeout. Вы можете создать иллюзию того, что несколько процессов делают что-то одновременно, хотя на самом деле все происходит в одном потоке.
Просто дайте вашей функции немного поработать, а затем вызовите что-то вроде:
setTimeout(function () {
... do the rest of the work...
}, 0);
И любые другие вещи, которые необходимо сделать (например, обновления пользовательского интерфейса, анимированные изображения и т. Д.), Произойдут, когда у них появится такая возможность.
loop
внутри setTimeout
, но, видимо, это не работает. Ты делал что-нибудь подобное или у тебя есть хак? пример будет для массива из 1000 элементов, я ожидаю использовать два цикла for внутри двух вызовов setTimeout
, так что первый проходит и печатает элемент 0..499
, второй проходит и печатает элемент 500..999
.
- person benjaminz; 01.11.2016
Вы имеете в виду, почему язык не поддерживает многопоточность или почему движки JavaScript в браузерах не поддерживают многопоточность?
Ответ на первый вопрос заключается в том, что JavaScript в браузере предназначен для запуска в изолированной программной среде и независимо от машины / ОС, добавление поддержки многопоточности усложнит язык и слишком тесно связывает язык с ОС.
Node.js 10.5+ поддерживает рабочие потоки как экспериментальную функцию (вы можете использовать ее с включенным флагом --experimental-worker): https://nodejs.org/api/worker_threads.html
Итак, правило такое:
- если вам нужно выполнить операции с привязкой к вводу-выводу, используйте внутренний механизм (также известный как обратный вызов / обещание / async-await)
- если вам нужно выполнить операции с привязкой к ЦП, используйте рабочие потоки.
Рабочие потоки предназначены для долгоживущих потоков, то есть вы создаете фоновый поток, а затем общаетесь с ним посредством передачи сообщений.
В противном случае, если вам нужно выполнить большую нагрузку на ЦП с помощью анонимной функции, вы можете использовать https://github.com/wilk/microjob, крошечная библиотека, построенная на рабочих потоках.
Как сказал Мэтт Би, вопрос не очень ясен. Предполагая, что вы спрашиваете о поддержке многопоточности на языке: потому что это не требуется для 99,999% приложений, работающих в настоящее время в браузере. Если вам это действительно нужно, есть обходные пути (например, с помощью window.setTimeout).
В общем, многопоточность очень, очень, очень, очень, очень, очень сложно (я сказал, что это сложно?), Если вы не наложите дополнительные ограничения (например, использование только неизменяемых данных).
Intel проводила исследования с открытым исходным кодом по многопоточности в Javascript, недавно они были продемонстрированы на GDC 2012. Вот ссылка на видео. Исследовательская группа использовала OpenCL, который в первую очередь ориентирован на наборы микросхем Intel и ОС Windows. Проект носит кодовое название RiverTrail, и его код доступен на GitHub.
Еще несколько полезных ссылок:
Создание вычислительной магистрали для веб-приложений
В настоящее время некоторые браузеры поддерживают многопоточность. Итак, если вам это нужно, вы можете использовать определенные библиотеки. Например, просмотрите следующие материалы:
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers (поддержка фоновых потоков);
https://keithwhor.github.io/multithread.js/ (библиотека).
Javascript - однопоточный язык. Это означает, что у него есть один стек вызовов и одна куча памяти. Как и ожидалось, он выполняет код по порядку и должен завершить выполнение фрагмента кода, прежде чем перейти к следующему. Это синхронно, но иногда это может быть вредно. Например, если функция требует времени для выполнения или должна что-то ждать, она тем временем все замораживает.
Это реализации, которые не поддерживают многопоточность. В настоящее время Google Gears предоставляет способ использования некоторой формы параллелизма путем выполнения внешних процессов, но не более того.
Новый браузер, который Google должен выпустить сегодня (Google Chrome), выполняет некоторый код параллельно, разделяя его в процессе.
Базовый язык, конечно, может иметь ту же поддержку, что, скажем, Java, но поддержка чего-то вроде параллелизма в Erlang далеко не за горами.
Насколько я слышал, в Google Chrome будет многопоточный javascript, так что это проблема «текущих реализаций».
Без надлежащей языковой поддержки для синхронизации потоков даже не имеет смысла пробовать новые реализации. Существующие сложные JS-приложения (например, все, что использует ExtJS), скорее всего, неожиданно завершат работу, но без ключевого слова synchronized
или чего-то подобного также было бы очень сложно или даже невозможно написать новые программы, которые ведут себя правильно.
Однако вы можете использовать функцию eval, чтобы довести параллелизм до некоторой степени.
/* 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;
}
}
Очевидно, что многопоточность с javascript возможна с использованием веб-работников, созданных с помощью HTML5.
Основное различие между веб-работниками и стандартной многопоточной средой заключается в том, что ресурсы памяти не используются совместно с основным потоком, ссылка на объект не видна из одного потока в другой. Потоки общаются посредством обмена сообщениями, поэтому можно реализовать алгоритм синхронизации и одновременного вызова методов, следуя шаблону проектирования, управляемому событиями.
Существует множество фреймворков, позволяющих структурировать программирование между потоками, среди них OODK-JS, фреймворк OOP js, поддерживающий параллельное программирование https://github.com/GOMServices/oodk-js-oop-for-js