Каковы недостатки создания многопоточной реализации JavaScript во время выполнения? [закрыто]

51

На прошлой неделе я работал над многопоточной реализацией JavaScript. У меня есть доказательство концепции, сделанной на C ++ с использованием JavaScriptCore и boost.

Архитектура проста: когда среда выполнения завершает оценку основного скрипта, который он запускает и присоединяется к пулу потоков, который начинает выбирать задачи из общей очереди приоритетов, если две задачи одновременно пытаются получить доступ к переменной, она помечается как атомарная и борется за доступ ,

Рабочая многопоточная среда выполнения node.js

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

У меня изначально была собственная реализация сопрограмм (использующая контексты повышения), но мне пришлось отказаться от нее (JavaScriptCore педантичен в отношении стека), и я не хотел рисковать их гневом, поэтому решил не упоминать об этом.

Как вы думаете? Должен ли JavaScript быть однопоточным, и его следует оставить в покое? Почему все против идеи одновременного выполнения JavaScript?

Изменить: Сейчас проект находится на GitHub , экспериментируйте с ним сами и дайте мне знать, что вы думаете.

Ниже приведено изображение обещаний, выполняемых на всех ядрах процессора параллельно без конфликтов:

Выполнение обещаний одновременно.

voodooattack
источник
7
Это похоже на очень самоуверенный вопрос. Вы спрашивали людей, которым, очевидно, не понравилась ваша идея, почему они думают, что это будет неприятно?
5gon12eder
26
Добавление потоков к чему-то, что не должно быть многопоточным, похоже на преобразование дороги с одной полосой в скоростную автомагистраль без предоставления водителя. В большинстве случаев это будет работать довольно хорошо, пока люди не начнут случайно падать. С многопоточностью у вас будут либо тонкие ошибки синхронизации, которые вы не можете воспроизвести, либо ошибочное поведение в большинстве случаев. Вы должны проектировать с учетом этого. Вам нужна синхронизация потоков. Простое превращение переменных в атомные не устраняет условия гонки.
mgw854
2
Как вы планируете обрабатывать многопоточный доступ к общему состоянию? «Отмечено как атомарное и претендует на доступ» не объясняет, как вы думаете, это действительно сработает. Я предполагаю, что негативное отношение к этой идее связано с тем, что люди не представляют, как на самом деле вы можете заставить эту работу работать. Или, если вы возлагаете на разработчика всю нагрузку, например, на Java или C ++, на использование надлежащих мьютексов и тому подобного, то люди, вероятно, думают, почему они хотят этого усложнения и риска программирования в среде, свободной от него.
jfriend00
17
Поскольку автоматическая координация случайного состояния между потоками считается почти невозможной проблемой, поэтому у вас нет уверенности в том, что вы можете предложить что-нибудь, что сделает это автоматически. И, если вы просто возьмете бремя на разработчика, как это делают Java или C ++, то большинство программистов node.js не хотят этого бремени - им нравится, что node.js не должен иметь дело с этим для большая часть. Если вы хотите более сочувствующий слух, вам нужно будет объяснить / показать, как и что вы предлагаете в этом отношении, и почему это было бы полезно и полезно.
jfriend00
3
Пожалуйста, продолжайте свою работу. Я считаю языки без многопоточности игрушечными языками. Я думаю, что большинство разработчиков JavaScript работают с браузером, который имеет однопоточную модель.
Хлоя

Ответы:

70

1) Многопоточность чрезвычайно сложна, и, к сожалению, то, как вы представили эту идею, подразумевает, что вы сильно недооцениваете ее сложность.

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

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

Добавление потоков в Javascript без «решения проблемы синхронизации» было бы похоже на добавление целых чисел в Javascript без «решения проблемы добавления». Это настолько фундаментально для природы проблемы, что нет смысла даже обсуждать, стоит ли добавлять многопоточность без конкретного решения, независимо от того, насколько сильно мы этого хотим.

Кроме того, превращение всех переменных в атомарные - это то, что может заставить многопоточные программы работать хуже, чем их однопоточные аналоги, что делает еще более важным на самом деле тестировать производительность на более реалистичных программах и посмотреть, получаете ли вы что-нибудь или нет.

Мне также не ясно, пытаетесь ли вы скрыть потоки от программиста node.js или планируете в какой-то момент разоблачить их, эффективно создавая новый диалект Javascript для многопоточного программирования. Оба варианта потенциально интересны, но, похоже, вы еще не определились, к какому из них вы стремитесь.

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

Наверное, поэтому люди не воспринимают тебя всерьез.

2) Простота и надежность единого цикла обработки событий является огромным преимуществом.

Программисты Javascript знают, что язык Javascript "безопасен" от условий гонки и других чрезвычайно коварных ошибок, которые мешают всему действительно многопоточному программированию. Тот факт, что им нужны веские аргументы, чтобы убедить их отказаться от того, что безопасность не делает их замкнутыми, делает их ответственными.

Если вы не можете каким-то образом сохранить эту безопасность, любому, кто захочет переключиться на многопоточный node.js, вероятно, было бы лучше перейти на язык наподобие Go, который изначально разрабатывался для многопоточных приложений.

3) Javascript уже поддерживает «фоновые потоки» (WebWorkers) и асинхронное программирование без непосредственного предоставления управления потоками программисту.

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

Есть ли у вас какие-то конкретные примеры использования, которые эти функции не решают, и для которых программисты Javascript хотят найти решение? Если это так, было бы неплохо представить ваш многопоточный файл node.js в контексте этого конкретного варианта использования.


PS Что бы убедило меня попробовать перейти на многопоточную реализацию node.js?

Напишите в Javascript / node.js нетривиальную программу, которая, по вашему мнению, выиграет от подлинной многопоточности. Выполните тесты производительности в этом примере программы на обычном узле и многопоточном узле. Покажите мне, что ваша версия в значительной степени повышает производительность, скорость отклика и использование нескольких ядер без каких-либо ошибок или нестабильности.

Как только вы это сделаете, я думаю, вы увидите, что люди гораздо больше заинтересованы в этой идее.

Ixrec
источник
1
1) Хорошо, я признаю, что уже некоторое время откладываю проблему синхронизации. Когда я говорю, что «будут бороться две задачи», это не мой дизайн, это в основном наблюдение: dl.dropboxusercontent.com/u/27714141/… - Я не уверен, какое колдовство JavaScriptCore выполняет здесь, но не должно ' Разве эта строка повреждена, если она не была атомарной? 2) Я категорически не согласен. По этой причине JS считается игрушечным языком. 3) Обещания ES6 были бы намного более производительными, если бы они реализовывались с использованием планировщика пула потоков.
voodooattack
13
@voodooattack «Вот почему JS считается игрушечным языком». Нет, по этой причине вы считаете это игрушечным языком. Миллионы людей используют JS каждый день и очень довольны им, недостатками и всем остальным. Удостоверьтесь, что вы решаете проблему, которую на самом деле имеет достаточно других людей, которая не может быть лучше решена простым изменением языков.
Крис Хейс
@ChrisHayes Вопрос в том, зачем мириться с его недостатками, когда я могу их исправить? Будет ли параллелизм как функция улучшать JavaScript?
voodooattack
1
@voodooattack Вот в чем вопрос. Будет ли параллелизм как функция улучшать Javascript? Если вы можете получить от сообщества ответ на этот вопрос, который не является «нет», то, возможно, вы что-то делаете. Однако кажется, что цикл событий и собственное делегирование Node рабочим потокам для блокирования событий достаточны для большей части того, что нужно делать людям. Я думаю, что если людям действительно нужен многопоточный Javascript, они будут использовать рабочие Javascript. Если вы можете найти способ заставить работников работать с первоклассными функциями вместо файлов JS, однако ... тогда вы действительно можете что- то делать.
lunchmeat317
7
@voodooattack Люди, которые называют JavaScript игрушечным языком, не знают, о чем говорят. Это общепринятый язык для всего? Конечно, нет, но отклонить это, как это, безусловно, ошибка. Если вы хотите развеять идею о том, что JS является игрушечным языком, то создайте в нем нетривиальное производственное приложение или укажите на существующее. В любом случае, просто добавление параллелизма не изменит этих людей.
jpmc26
16

Просто угадать здесь, чтобы продемонстрировать проблему в вашем подходе. Я не могу проверить это с реальной реализацией, так как нигде нет ссылки ...

Я бы сказал, что это потому, что инварианты не всегда выражаются значением одной переменной, и «одной переменной» недостаточно для того, чтобы быть областью блокировки в общем случае. Например, представьте, что у нас есть инвариант a+b = 0(баланс банка с двумя счетами). Две нижеприведенные функции гарантируют, что инвариант всегда сохраняется в конце каждой функции (единица выполнения в однопоточном JS).

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

Теперь в вашем многопоточном мире, что происходит , когда два потока выполнения , withdrawи depositв то же время? Спасибо, Мерфи ...

(Возможно, у вас есть код, который обрабатывает + = и - = специально, но это не поможет. В какой-то момент у вас будет локальное состояние в функции, и без возможности «заблокировать» две переменные одновременно ваш инвариант будет быть нарушенным.)


РЕДАКТИРОВАТЬ: Если ваш код семантически эквивалентен коду Go на https://gist.github.com/thriqon/f94c10a45b7e0bf656781b0f4a07292a , мой комментарий точен ;-)

thriqon
источник
Этот комментарий не имеет значения, но философы способны блокировать несколько объектов, но они голодают, потому что блокируют их в непоследовательном порядке.
Дитрих Эпп
3
@voodooattack "Я только что проверил ..." Вы никогда не сталкивались с непоследовательным порядком выполнения с планированием потоков? Это варьируется от бега к бегу, от машины к машине. Сидеть и запускать один тест (или даже сотню тестов!) Без определения механизма планирования операций бесполезно.
jpmc26
4
@voodooattack Проблема в том, что простое тестирование параллелизма бесполезно. Вы должны быть в состоянии доказать, что инвариант будет держаться, или механизму никогда нельзя доверять в производстве.
Сапи
1
Но вы не дали пользователю никаких инструментов, чтобы «использовать систему ответственно», потому что нет абсолютно никакого механизма блокировки. Создание всего атомарного дает иллюзию безопасности потоков (и вы получаете удар по производительности всего атомарного, даже когда вам не нужен атомарный доступ), но на самом деле это не решает большинство проблем параллелизма, подобных тем, что дает тригон. В другом примере попробуйте выполнить итерацию по массиву в одном потоке, в то время как другой поток добавляет или удаляет элементы из массива. В связи с этим, что заставляет вас думать, что реализация Array в двигателе является даже поточно-ориентированной?
Зак Липтон
2
@voodooattack Так что, если пользователи могут использовать ваши потоки только для функций без общих данных или побочных эффектов (и им лучше не использовать их ни для чего другого, потому что, как мы видели здесь, нет способа обеспечить безопасность потоков), тогда какое значение вы предоставляете веб-работникам (или одной из многих библиотек, предоставляющих более удобный API для веб-работников)? А веб-работникам намного безопаснее, потому что они лишают пользователя возможности использовать систему «безответственно».
Зак Липтон
15

Примерно десять лет назад Брендан Эйх (изобретатель JavaScript) написал эссе под названием Threads Suck , которое определенно является одним из немногих канонических документов мифологии дизайна JavaScript.

Правильно ли это - другой вопрос, но я думаю, что это сильно повлияло на то, как сообщество JavaScript думает о параллелизме.

Эрик Пукинскис
источник
31
Последний человек, от которого я бы посоветовался, это Брендан Эйх. Вся его карьера основана на создании JavaScript, который настолько плох, что у нас есть куча инструментов, созданных для того, чтобы попытаться обойти его врожденную дрянь. Подумайте, сколько часов разработчиков было потрачено впустую в мире из-за него.
Фил Райт
12
Хотя я понимаю, почему вы вообще не принимаете во внимание его мнение, и даже ваше презрение к JavaScript, я не понимаю, как ваша точка зрения позволила бы игнорировать его опыт в этой области.
Билли Крейвенс
4
@BillyCravens хаха, даже каноническая книга по Javascript: «Javascript the good parts » Крокфорда выдает игру в названии. Относитесь к отношениям Эйха таким же образом, просто придерживайтесь того, что он говорит, что это хорошо :-)
gbjbaanb
13
@PhilWright: Его первая реализация Javascript была вариантом Lisp. Который мне приносит ему огромное уважение. Решение его босса заставить его заменить синтаксис Lisp на C-подобный синтаксис не является его ошибкой. По своей сути Javascript по-прежнему является средой исполнения Lisp.
Slebetman
7
@PhilWright: Вы не должны винить Эйха за глупость языка. Это ошибки в ранних реализациях и необходимость обратной совместимости для веб-языка, который препятствовал зрелости JS. Основные понятия все еще формируют замечательный язык.
Берги
8

Атомарный доступ не приводит к поточно-ориентированному поведению.

Один из примеров - когда глобальная структура данных должна быть недействительной во время обновления, такого как перефразирование хэш-карты (например, при добавлении свойства к объекту) или сортировка глобального массива. В течение этого времени вы не можете разрешить другим потокам доступ к переменной. Это в основном означает, что вам нужно обнаружить все циклы чтения-обновления-записи и заблокировать их. Если обновление не тривиально, это приведет к остановке проблемной территории.

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

Это имеет большое преимущество в отношении изолированных контекстов и позволяет двум отдельным контекстам работать в разных потоках. Я также имею в виду, что людям, пишущим javascript, не нужно знать, как справляться с условиями гонки и различными другими многопоточными питалами.

чокнутый урод
источник
Вот почему я считаю, что API планировщика должен быть более продвинутым и внутренне использоваться для обещаний и функций, которые не имеют побочных эффектов.
voodooattack
6

Ваш подход собирается значительно улучшить производительность?

Сомнительно. Вам действительно нужно это доказать.

Ваш подход облегчит / ускорит написание кода?

Определенно нет, многопоточный код во много раз сложнее понять, чем однопоточный код.

Ваш подход будет более надежным?

Тупики, условия гонки и т. Д. - это кошмар, который нужно исправить.

Фил Райт
источник
2
Попробуйте собрать raytracer с помощью node.js, теперь попробуйте снова с потоками. Многопроцессность это еще не все.
Voodooattack
8
@voodooattack, никто в здравом уме не написал бы трассировщик лучей, используя javascript, с потоками или без них, потому что это относительно простой, но требовательный к вычислениям алгоритм, который лучше писать на полностью скомпилированном языке, предпочтительно с поддержкой SIMD , Для задач, для которых используется javascript, многопроцессорности более чем достаточно.
Ян Худек
@JanHudec: Хех, JS также получит поддержку SIMD :-) hacks.mozilla.org/2014/10/introduction-simd-js
Берги
2
@voodooattack Если вы не знаете о них, взгляните на SharedArrayBuffers . JavaScript получает больше конструкций параллелизма, но они добавляются крайне осторожно, обращаясь к конкретным болевым точкам, пытаясь свести к минимуму принятие плохих проектных решений, с которыми нам придется жить годами.
ВОССТАНОВИТЬ МОНИКУ
2

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

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

Анкур
источник
1
Я думаю, что обещания ES6 выиграют от модели моей реализации, так как они не борются за доступ.
Voodooattack
Посмотрите на спецификацию WebWorkers. Существуют пакеты npm, которые обеспечивают их реализацию, но вы можете реализовать их как ядро ​​своего движка, а не как пакет
Ankur
JavaScriptCore (реализация JS, которую я использую в Webkit) уже реализует их, это всего лишь флаг компиляции.
Voodooattack
Хорошо. WebWorkers параллельны с передачей сообщений. Вы можете попробовать ваш пример с raytracer и сравнить его с подходом изменяемого состояния.
Анкур
4
Передача сообщений всегда осуществляется поверх изменяемого состояния, что означает, что это будет медленнее. Я не вижу твоей точки зрения здесь. : - /
voodooattack
1

Это необходимо Отсутствие низкоуровневого механизма параллелизма в узле js ограничивает его применение в таких областях, как математика, биоинформатика и т. Д. Кроме того, параллелизм с потоками не обязательно конфликтует с моделью параллелизма по умолчанию, используемой в узле. Существует хорошо известная семантика потоков в среде с основным циклом событий, такой как пользовательские среды (и nodejs), и они определенно слишком сложны для большинства ситуаций, в которых они все еще используются.

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

dryajov
источник
4
Но «математику и биоинформатику» лучше написать на C #, JAVA или C ++
Ian
На самом деле Python и Perl являются доминирующими языками в этих областях.
Dryajov
1
На самом деле, главная причина, по которой я это реализую, заключается в приложениях машинного обучения. Таким образом, у вас есть точка зрения.
voodooattack
@dryajov Радуйтесь, что вы не знаете, насколько велик Фортран в некоторых областях вычислительной науки ...
cmaster
@dryajov Потому что они более доступны для людей, которые, возможно, не являются программистами на полную ставку, а не потому, что они по своей природе лучше разбираются в секвенировании генома - у нас есть специально созданные языки, такие как R, и скомпилированные научные языки, такие как Fortran.
кот
0

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

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

Джейсон Ливесей
источник
Вы имеете в виду, что программисты JS привязаны к поставщику на npm?
Voodooattack
3
Речь идет о новой системе времени выполнения, а не о каком-то модуле npm, а также об изменчивом параллельном совместном использовании состояний - это на самом деле старая идея.
Анкур
1
@voodooattack Я имею в виду, что у них есть мозговой барьер к подходу, который уже популярен, и будет почти невозможно преодолеть предвзятость статус-кво.
Джейсон Ливай