Язык программирования, где каждый вызов функции / блок выполняется в отдельном потоке? [закрыто]

26

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

Я не очень осведомлен о многопоточном, параллельном программировании, но я знаю основы (Futures, объекты, защищенные от потоков). Поэтому мне интересно, как такой язык может выглядеть с точки зрения синтаксиса и возможно ли вообще начать с него? Цель состоит не в том, чтобы сделать его «полезным», а в большей степени для удовольствия и обучения.

(Извините, если это неправильное место для публикации. Если это так, я был бы рад, если вы укажете мне правильное место, где разрешен вопрос, подобный моему.)

Grimbox
источник
17
Создавать темы просто. Хитрость с многопоточностью заключается в том, что им нужно общаться друг с другом или работать с одними и теми же ресурсами. Другими словами, это не разветвление, а соединение. Главная проблема, которую вам нужно решить, это то, как вы это контролируете.
JimmyJames
20
ИМО, вы не можете сделать это без серьезного растягивания обычного определения слова «функция» или слова «нить». Возможно, вы захотите прочитать об актерах, если вы еще не знакомы с ними: en.wikipedia.org/wiki/Actor_model
Solomon Slow
9
Получите достаточную детализацию, и вы обнаружите, что процессоры уже распараллеливают инструкции автоматически, без дополнительной нагрузки на разработчика программного обеспечения. См. Выполнение не по порядку и суперскалярный процессор .
8bittree
8
Это на самом деле звучит ужасно. Я собирался объяснить, почему, но Карл Билефельдт уже сделал.
Мейсон Уилер
1
Какую парадигму вы хотите поддержать на своем языке? Должен ли он быть императивным или функциональным? Вы говорите, что все операторы будут выполняться одновременно - блоки then / else вместе с тем, что идет после них?
Берги

Ответы:

39

каждый вызов функции / новый блок (если предложения, циклы и т. д.) будет работать в отдельном потоке.

Прочитайте больше о продолжениях и стиле прохождения продолжения (и их отношении к потокам или сопрограммам). Я предлагаю прочитать SICP & Lisp In Small Pieces . Кроме того, язык программирования Pragmatics дает полезный обзор нескольких языков и поможет вам создать свой собственный.

Поэтому мне интересно, как такой язык может выглядеть синтаксически мудрым

Синтаксис не имеет большого значения для изучения идей . Семантика имеет гораздо большее значение. Я предлагаю сначала использовать синтаксис типа S-expr (чтобы вы могли создавать прототипы, используя Scheme и ее вызов / cc ).

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

Василий Старынкевич
источник
25
+1 за упоминание о том, почему синтаксис не имеет значения. Еще один +1, если бы я мог объяснить, почему синтаксис очень важен.
Йорг Миттаг
Хорошее предложение, но для обсуждения вещей на LtU вы хотели бы иметь аккаунт, а получить его из моего опыта не тривиально.
Mael
1
Вы должны использовать пул потоков, чтобы уменьшить накладные расходы. en.wikipedia.org/wiki/Thread_pool
shawnhcorey
37

Возможно, вам будет интересно почитать об исследовании параллельных данных на Haskell . Если вы будете искать на YouTube, Саймон Пейтон Джонс выступил с некоторыми интересными докладами, связанными с этой темой.

Если я правильно помню из его выступлений, в чисто функциональном программировании почти тривиально найти возможности для создания потоков. Его главная проблема в его исследованиях - иметь слишком много слишком коротких, так что накладные расходы на создание потоков и передачу их результатов существенно перевешивают преимущества параллелизма. Например, легко научить компилятор раскручивать до 100 потоков для вычислений sum $ fmap (+1) <100 length vector>, но стоит ли это делать?

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

Карл Билефельдт
источник
8
Я уже был бы счастлив работать со старомодным ПК с сотнями ядер ...
Хаген фон
8
Я хотел бы отметить, что для проектов с высокой степенью параллелизма данных мы уже очень эффективно выполняем много параллелизации: графические процессоры - это, по сути, 200-1000 ядерных машин (у них даже есть своя собственная иерархия памяти).
Делиот
4
@HagenvonEitzen: JCA Azul Vega (Java Compute Appliance) имел 16 процессоров с 54 ядрами на 864 ядра, и это был не какой-то исследовательский или прототипный компьютер, а настоящий продукт. Это также не заполняло целое здание или даже целую комнату, это было устройство размера стола. И это было доступно 9 лет назад. Графические процессоры уже упоминались, однако это была машина с 864 ядрами общего назначения .
Йорг Миттаг
3
Конечно, есть причина, по которой у нас сегодня есть эти массивные параллельные графические процессоры, но уже нет этих массивных многоядерных процессоров для настольных ПК. Первые коммерчески жизнеспособны, вторые - нет, и это потому, что вы не могли эффективно их программировать.
MSalters
@MSalters, может быть, нам просто нужно бесконечное количество обезьян? Или программы Quantum, которые просто запускают все возможные операции на каждом шаге?
15

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

GenericJam
источник
4

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

Если говорить более абстрактно, то π-исчисление является прекрасным подходом к моделированию параллельных вычислений. Трудно разобраться, если вы не достанете книгу Робин Милнер « Коммуникационные и мобильные системы: исчисление Пи ». Это помогло мне подумать о параллельных вычислениях в более широком смысле, так как «несколько потоков обращаются к общей памяти». Интересно, как условные выражения, "gotos" и т. Д. Могут быть построены из более простых, естественно параллельных примитивов.

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

Artelius
источник
4

Подобные проекты были предприняты в прошлом. Я предлагаю читать классику, чтобы добыть идеи. (Все ссылки идут на Википедию)

  • Unity Этот язык использовался / используется для обучения параллельному программированию. Я не думаю, что это было на самом деле реализовано. Синтаксис несколько загадочный, но в основном у вас есть набор операторов, которые выполняются в неизвестном порядке и многократно, пока больше ничего не будет сделано. Это ближе всего к тому, что вы просите.

  • Occam Этот язык был разработан для реального использования, но он никогда не завоевывал популярность. Здесь есть ключевое слово PAR, которое означает, что список операторов должен выполняться параллельно.

  • Эрланг Другой язык реального мира. Этот используется телекоммуникационной компанией Ericsson и имеет довольно много последователей. Они приложили много усилий, чтобы сделать параллелизм практичным и полезным.

  • Google GO Это моя любимая группа. Концептуально почти так же, как Erlang, но с лучшим синтаксисом и весом Google за ним. Что может пойти не так?

Я хотел бы закончить с предупреждением: параллелизм очень трудно понять правильно. Большинство ошибок в современных программах - результат неправильного понимания . Вы уверены, что хотите пойти туда?

Стиг Хеммер
источник
Без обид на любой язык, которого нет в моем списке. Просто мои знания ограничены.
Стиг Хеммер
3

Это возможно, но это не будет полезно для 99 +% всех мыслимых приложений. Логика типично привязана к последовательности, это поток. Шаг за шагом вы достигаете решения проблемы, и порядок шагов имеет значение, главным образом потому, что выходные данные одного шага будут входными для следующего.

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

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

Мартин Маат
источник
5
Это отличный ответ на другой вопрос; OP спрашивает не о целесообразности такой схемы, а просто о том, можно ли это сделать и как будет выглядеть «синтаксис».
ДепрессияДаниэль
9
Те, кто не просят об этом, больше всего нуждаются в моей мудрости. Если кто-то спросит, можно ли спуститься с горки в корзине, лучшим ответом будет не «Ставь! Обязательно смазывай их колесами!». Это было бы больше похоже на «Ну, да, но ...».
Мартин Маат
Напоминает мне старую инструкцию по языку ассемблера EIAO - Выполнять в любом порядке . (И где же этот Any Key?)
@MartinMaat никто не собирается убивать себя, написав язык программирования для развлечения
user253751
2

Clojure может стоить посмотреть на некоторые идеи.

http://clojure-doc.org/articles/language/concurrency_and_parallelism.html

Вот некоторые соображения: если мы называем вычислительную единицу, которая может быть выполнена независимо, задачей: 1. Задачи независимы, поэтому могут выполняться одновременно 2. Для разных задач требуются разные ресурсы и для их выполнения требуется разное время 3. Поэтому задачи должны планироваться для максимальной пропускной способности 4. Единственная программа, которая может выполнять функции планировщика, - это операционная система

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

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

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

Вышесказанное, вероятно, означает, что динамические языки и своевременная компиляция - это путь.

Foobar
источник
2

То, что вы ищете, называется неявным параллелизмом, и есть языки, которые исследовали эту концепцию, такие как Sun / Oracle Fortress . Помимо прочего, он (потенциально) запускает циклы параллельно.

К сожалению, оно было прекращено, и есть много мертвых ссылок, но вы все равно можете найти несколько PDF-файлов, если вы достаточно усердно гуглите:

https://www.eecis.udel.edu/~cavazos/cisc879-spring2008/papers/fortress.pdf (спецификация языка)

http://stephane.ducasse.free.fr/Teaching/CoursAnnecy/0506-Master/ForPresentations/Fortress-PLDITutorialSlides9Jun2006.pdf

http://www.oracle.com/technetwork/systems/ts-5206-159453.pdf

http://dl.acm.org/citation.cfm?id=1122972 (paywalled)

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

gustafc
источник
1
+1 за упоминание о Крепости ... Мне очень понравилась идея языка. Мне было очень грустно, когда они объявили, что разработка была прекращена ...
Роланд
2

Хотя это и не язык программирования как таковой, вы должны взглянуть на VHDL . Он используется для описания цифровых схем, которые, естественно, делают все параллельно, если вы не указали это делать последовательно. Это может дать вам некоторые идеи, как разработать свой язык и для какой логики он может подойти.

OnePie
источник
0

Это может быть легко смоделировано в C ++. Просто убедитесь, что «каждый» * вызов функции реализован с помощью std::future. Обработка возвращаемого значения просто осуществляется путем вызова .get()на будущее.

Следовательно, вы можете создать прототип своего языка путем компиляции в C ++. Это также говорит нам о том, как будет выглядеть синтаксис: главное отличие состоит в том, что вы отделяете точку вызова (где предоставляются входные аргументы) от точки возврата (где используется выход функции).

(*) Я говорю «каждая функция», но вам решать, что считать функцией. Это memsetвстроенная или функция? Является ли присвоение целых чисел или присвоение пользовательских типов вызовом функции?

MSalters
источник
И если вы откладываете ответ на вопрос достаточно долго, обычно необходимость в ответе уходит. Я думаю, что это называется «Lazy Existing».