Почему JavaScript не поддерживает многопоточность?


269

Это преднамеренное дизайнерское решение или проблема с нашими современными браузерами, которые будут исправлены в следующих версиях?


3
См. Также ответы на вопрос JavaScript и Threads для получения информации о веб-работниках / рабочих потоках.
Сэм Хаслер

115
Привет, приятель Гуглер. Вы можете заметить, что все здесь выглядит довольно устаревшим (обратите внимание, что этот вопрос был задан более 5 лет назад). С тех пор, как его спросили, веб-браузеры получили некоторые возможности, которые, насколько я могу судить, являются более или менее многопоточными. Взгляните на веб-работников: msdn.microsoft.com/en-us/hh549259.aspx
ArtOfWarfare,

2
Multithread.js оборачивает веб-работников и обеспечивает простую многопоточность в JS. Работает на всех новых браузерах, включая iOS Safari. :)
kwh

1
Возможный дубликат JavaScript и Threads
Мэтт

Ответы:


194

JavaScript не поддерживает многопоточность, потому что интерпретатор JavaScript в браузере является однопоточным (AFAIK). Даже Google Chrome не позволяет одновременно запускать JavaScript-код одной веб-страницы, поскольку это может вызвать серьезные проблемы с параллелизмом на существующих веб-страницах. Все, что делает Chrome - это разделяет несколько компонентов (разные вкладки, плагины и т. Д.) На отдельные процессы, но я не могу представить, чтобы на одной странице было несколько потоков JavaScript.

Тем не менее, вы можете использовать, как было предложено, setTimeoutдля какого-то планирования и «ложного» параллелизма. Это приводит к тому, что браузер восстанавливает контроль над потоком рендеринга и запускает код JavaScript, предоставленный setTimeoutчерез указанное количество миллисекунд. Это очень полезно, если вы хотите, чтобы окно просмотра (что вы видите) обновлялось при выполнении операций с ним. Простое прохождение, например, координат и обновление элемента соответственно, позволит вам увидеть начальную и конечную позиции, и ничего между ними.

Мы используем библиотеку абстракций в JavaScript, которая позволяет нам создавать процессы и потоки, которые управляются одним и тем же интерпретатором JavaScript. Это позволяет нам выполнять действия следующим образом:

  • Процесс А, Поток 1
  • Процесс А, Поток 2
  • Процесс Б, Поток 1
  • Процесс А, Поток 3
  • Процесс А, Поток 4
  • Процесс Б, Поток 2
  • Пауза Процесс А
  • Процесс B, Поток 3
  • Процесс B, Поток 4
  • Процесс B, Поток 5
  • Начать процесс A
  • Процесс А, Поток 5

Это допускает некоторую форму планирования и ложного параллелизма, запуска и остановки потоков и т. Д., Но это не будет настоящей многопоточностью. Я не думаю, что это когда-либо будет реализовано в самом языке, поскольку настоящая многопоточность полезна только в том случае, если браузер может запускать многопоточную одностраничную страницу (или даже более одного ядра), а трудности там намного больше. чем дополнительные возможности.

Для будущего JavaScript, проверьте это: https://developer.mozilla.org/presentations/xtech2006/javascript/


73
Я думаю, что никогда не реализовано слишком узкое видение. Я гарантирую, что в конечном итоге веб-приложения смогут быть действительно многопоточными (это логично, поскольку веб-приложения становятся все более доминирующими, а оборудование становится более параллельным), и, как я вижу, поскольку JavaScript является де-факто языком веб-разработки, он в конечном итоге придется поддерживать многопоточность или заменить что-то, что делает.
devios1

6
Никогда, наверное, не слишком смелое утверждение :), но я все еще думаю, что преимущества настоящего многопоточного javascript нереализуемы в обозримом будущем;)
Kamiel Wanrooij

5
Хотя я бы сказал, что веб-работники более параллельны через модель процесса, чем модель потока. Веб-работники используют передачу сообщений в качестве средства связи, что является элегантным решением «обычных» проблем параллелизма в многопоточных приложениях. Я не уверен, могут ли они одновременно работать с теми же объектами, что и главная страница. Насколько я знаю, они не могут получить доступ к DOM. Большая часть этого - семантика, хотя, веб-работники выглядят многообещающе для всех намерений и целей.
Kamiel Wanrooij

трудности там намного больше, чем дополнительные возможности. Я не уверен, что вы думаете обо всех дополнительных возможностях. Я особенно думаю о случаях, когда webgl используется как в играх или графических визуализациях. Например, рассмотрим новую 3D-версию Google Maps. В городах со многими 3D-моделями моему ПК требуется ~ 2 минуты, чтобы загрузить все, когда нужно рендерить много домов. Под определенными углами ни моя видеокарта, ни моя сеть не работают на полную мощность. Но 1 из 8 процессоров на 100%. Многопоточность также является большой проблемой с точки зрения fps, как показано в этом примере: youtube.com/watch?v=sJ2p982cZFc
Scindix

25

Многопоточность JavaScript (с некоторыми ограничениями) здесь. Google внедрил рабочих для Gears, а рабочие включены в HTML5. Большинство браузеров уже добавили поддержку этой функции.

Потоковая безопасность данных гарантируется, потому что все данные, передаваемые в / из работника, сериализуются / копируются.

Для получения дополнительной информации читайте:

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

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


8
Но разве это не многопоточный подход, а не многопоточный? Известно, что потоки работают в одной куче.
beefeather

1
@ beefeather, это правда. Это скорее процессный подход.
Нил

23

Традиционно JS предназначался для коротких, быстро выполняющихся фрагментов кода. Если у вас были серьезные вычисления, вы делали это на сервере - идея приложения JS + HTML , которое долгое время работало в вашем браузере и делало нетривиальные вещи, было абсурдным.

Конечно, теперь у нас есть это. Но браузерам понадобится немало времени, чтобы наверстать упущенное - большинство из них было разработано на основе однопоточной модели, и изменить ее непросто. Google Gears обходит многие потенциальные проблемы, требуя изолированного фонового выполнения - не нужно менять DOM (так как это не является потокобезопасным), нет доступа к объектам, созданным основным потоком (так же). Несмотря на ограниченность, это, вероятно, будет наиболее практичным дизайном для ближайшего будущего, поскольку он упрощает дизайн браузера и снижает риск, связанный с тем, что неопытные JS-кодеры могут связываться с потоками ...

@marcio :

Почему это не является причиной реализации многопоточности в Javascript? Программисты могут делать с инструментами все, что хотят.

Итак, давайте не будем давать им инструменты, которыми так легко злоупотреблять, что любой другой веб-сайт, который я открываю, приводит к сбою моего браузера. Наивная реализация этого привела бы вас прямо на территорию, которая вызывала много головных болей у MS во время разработки IE7: авторы дополнений быстро и свободно играли с моделью потоков, что приводило к скрытым ошибкам, которые становились очевидными, когда жизненные циклы объектов менялись в основном потоке , ПЛОХОЙ. Если вы пишете многопоточные дополнения ActiveX для IE, я думаю, это идет с территорией; не значит, что нужно идти дальше.


6
«это снижает риск, связанный с тем, что неопытные JS-кодеры могут> возиться с потоками». Почему это не является причиной реализации многопоточности в Javascript? Программисты могут делать с инструментами все, что хотят. Хорошо это или плохо, но это их проблема. С моделью процесса Google Chrome это не может повлиять даже на другие приложения. :)
Марсио Агиар

3
@ Shog9 - «Давайте не будем давать [программистам] инструменты, которыми так легко злоупотреблять, что любой другой веб-сайт, который я открываю, приводит к сбою моего браузера». - Какой? По той же логике, ни у одного языка не должно быть многопоточности, потому что, если бы они предложили, что любая другая программа, которую вы пытались открыть, вылетала. За исключением того, что это не работает таким образом. Многопоточность существует в большинстве языков, и большинство начинающих программистов ее не трогают, а также большинство тех, кто ее не использует, и те приложения, которые никогда не становятся популярными или широко используемыми.
ArtOfWarfare

11

Я не знаю обоснования этого решения, но я знаю, что вы можете смоделировать некоторые преимущества многопоточного программирования с помощью setTimeout. Вы можете создать иллюзию того, что несколько процессов делают что-то одновременно, хотя в действительности все происходит в одном потоке.

Просто сделайте так, чтобы ваша функция немного поработала, а затем вызовите что-то вроде:

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

И любые другие вещи, которые нужно сделать (например, обновления пользовательского интерфейса, анимированные изображения и т. Д.), Произойдут, когда они получат шанс.


В большинстве случаев я хотел бы использовать loopвнутри, setTimeoutно, видимо, это не работает. Вы сделали что-нибудь подобное или у вас есть взлом? Например, для массива из 1000 элементов я ожидаю использовать два setTimeoutцикла for в двух вызовах, так что первый цикл проходит и печатает элемент 0..499, второй - цикл и печатает элемент 500..999.
Бенджаминз

Обычно техника заключается в том, чтобы сохранить состояние и продолжить. Например, допустим, что вы хотите вывести от 0 до 1000, вы можете вывести от 0 до 499, а затем выполнить трюк setTimeout с аргументом 500. Код внутри будет знать, что нужно взять аргумент (500) и запустить цикл оттуда.
Эяль

8

Вы имеете в виду, почему язык не поддерживает многопоточность или почему движки JavaScript в браузерах не поддерживают многопоточность?

Ответ на первый вопрос заключается в том, что JavaScript в браузере предназначен для запуска в песочнице и независимым от машины / ОС способом, чтобы добавить поддержку многопоточности усложнил бы язык и слишком привязал бы язык к ОС.


6

Node.js 10.5+ поддерживает рабочие потоки в качестве экспериментальной функции (вы можете использовать ее с включенным флагом --experimental-worker ): https://nodejs.org/api/worker_threads.html

Итак, правило таково:

  • если вам нужно выполнить операции ввода-вывода с привязкой , то используйте внутренний механизм (он же callback / обещание / async-await)
  • если вам нужно выполнить операции с привязкой к процессору , используйте рабочие потоки.

Рабочие потоки предназначены для долгоживущих потоков, то есть вы создаете фоновый поток, а затем общаетесь с ним посредством передачи сообщений.

В противном случае, если вам необходимо выполнить большую загрузку ЦП с помощью анонимной функции, вы можете воспользоваться https://github.com/wilk/microjob , крошечной библиотекой, построенной на рабочих потоках.


4

Как сказал Мэтт Б, вопрос не очень ясен. Предположим, что вы спрашиваете о поддержке многопоточности на языке: потому что это не требуется для 99,999% приложений, работающих в браузере в настоящее время. Если вам это действительно нужно, есть обходные пути (например, использование window.setTimeout).

В общем случае многопоточность очень, очень, очень, очень, очень, очень, очень трудно (я говорил, что это сложно?) Получить правильные результаты, если вы не вводите дополнительные ограничения (например, использование только неизменных данных).


3

Корпорация Intel провела несколько исследований с открытым исходным кодом о многопоточности в Javascript, недавно она была продемонстрирована на GDC 2012. Вот ссылка на видео . Исследовательская группа использовала OpenCL, которая в первую очередь ориентирована на наборы микросхем Intel и ОС Windows. Проект с кодовым названием RiverTrail и код доступен на GitHub

Еще несколько полезных ссылок:

Создание вычислительного шоссе для веб-приложений


2

В настоящее время некоторые браузеры поддерживают многопоточность. Итак, если вам это нужно, вы можете использовать определенные библиотеки. Например, просмотрите следующие материалы:


1

Это реализации, которые не поддерживают многопоточность. В настоящее время Google Gears предоставляет способ использовать некоторую форму параллелизма, выполняя внешние процессы, но это все.

Новый браузер, который Google должен выпустить сегодня (Google Chrome), выполняет некоторый код параллельно, разделяя его в процессе.

Основной язык, конечно, может иметь такую ​​же поддержку, как, скажем, Java, но поддержка чего-то вроде параллелизма Эрланга далеко не за горизонтом.


1

Javascript - это однопоточный язык. Это означает, что у него один стек вызовов и одна куча памяти. Как и ожидалось, он выполняет код по порядку и должен завершить выполнение фрагмента кода, прежде чем перейти к следующему. Это синхронно, но иногда это может быть вредно. Например, если функция выполняется некоторое время или должна что-то ждать, она тем временем замораживает все.


0

Насколько я слышал, в Google Chrome будет многопоточный JavaScript, так что это проблема "текущих реализаций".


0

Без надлежащей языковой поддержки синхронизации потоков даже не имеет смысла пробовать новые реализации. Существующие сложные приложения JS (например, что-либо, использующее ExtJS), скорее всего, неожиданно завершат работу, но без synchronizedключевого слова или чего-либо подобного, будет также очень трудно или даже невозможно написать новые программы, которые ведут себя правильно.


-1

Однако вы можете использовать функцию 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;
    }
}

-2

Многопоточность с использованием javascript, безусловно, возможна с помощью веб-разработчиков HTML5.

Основное различие между веб-работниками и стандартной многопоточной средой заключается в том, что ресурсы памяти не используются совместно с основным потоком, ссылка на объект не видна из одного потока в другой. Потоки взаимодействуют посредством обмена сообщениями, поэтому возможно реализовать алгоритм синхронизации и одновременного вызова метода, следуя шаблону проектирования, управляемого событиями.

Существует множество платформ, позволяющих структурировать программирование между потоками, в том числе OODK-JS, фреймворк OOP js, поддерживающий параллельное программирование https://github.com/GOMServices/oodk-js-oop-for-js


5
Совместное использование памяти - это точное определение потока, противоположного отдельному процессу (например, fork () против exec ()). Потоки могут совместно использовать объекты, процессы должны использовать IPC. Веб-работники не многопоточность.
felixfbecker
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.