Здравствуйте, VladD2, Вы писали:
VD>Возвращаемся к тем же файлам. Вот отпарсили мы файл в отдельном потоке. Теперь надо сделать так, чтобы я мог обработать полученные данные (а их очень много) параллельно с остальными данными (из других файлов) и при этом не иметь проблем с блокировками и не копировать все данные.
Звучит как типичная задача для futures + immutable структур данных. Причем числодробильные части (вроде парсера считанного файла и прочих строго алгоритмических замкнутых шагов) про Futures ничего знать не будут, это будет во внешнем (координирующем) коде.
VD>Для того нужно чтобы программист оперировал некими областями памяти которые можно изменят только из одного потока управления.
Локальные переменные
VD>И предоставить программисту дешевый способ передачи "замороженного слепа информации" из одного потока в другой.
Immutable типы.
VD>Иными словами нужно сделать так, чтобы потоки не имели общих данных, а передача данных из одного потока в другой была прозрачной и дешевой.
Не имели общих изменяемых данных. Не вижу никаких проблем в неизменяемых данных, разделяемых многими потоками. Передача незименяемых данных — простая и прозрачная. Чистота API (immutable in, immutable out) достигается ревью кода. Внутри методов — пусть изменяемые структуры используют, не жалко.
VD>Нужно научить языки манипулировать кучами. Научить передавать эти кучи между "виртуальными процессами" (в стиле Эрланг).
И программистов тоже этому учить? А сколько там выиграть планируется по сравнению с futures+immutable structures? Я ради двух-трех раз в разнице производительности вряд ли буду учить новый язык и кучу вручную на области размечать. За immutable плата есть, но относительно небольшая (чуть менее оптимальные структуры, лишний lookup вместо циклов). Если припрет, я скорее будут смотреть на кластер по компиляции. Потому что в чистых функциях и ациклических графах выносить отдельные операции на кластер можно легко и просто. Почти ничего не поменяется. Было Future, вычисляющееся в потоке. Будет Future, получающее данные из сети. Можно еще всякие shared fs + caches посмотреть и т.п. Но это вряд ли скоро понадобится.
Здравствуйте, Khimik, Вы писали:
K>Здравствуйте, kov_serg, Вы писали:
_>>Языки 4-го поколения например sql. Где компилятор сам синтезирует и распаралеливает алгоритм.
K>На SQL Doom не напишешь...
"Как мыло вы знаете про добрых фей". На js написали же.
Сори за задержку с ответом. Заметил ответ только сейчас.
VD>>Возвращаемся к тем же файлам. Вот отпарсили мы файл в отдельном потоке. Теперь надо сделать так, чтобы я мог обработать полученные данные (а их очень много) параллельно с остальными данными (из других файлов) и при этом не иметь проблем с блокировками и не копировать все данные.
M>Звучит как типичная задача для futures + immutable структур данных.
Использование неизменяемых структур — это паттерн программирования. Проблема любого паттерна в том, что его можно легко нарушить. А контроля нет!
Если язык не "чисто функциональный" (по сути таких и не бывает), то нет возможности гарантировать, что чужая локальная память не изменяется.
Кроме того далеко не все алгоритмы можно эффективно реализовать на базе неизменяемых структур данных. Зачастую императивное решение гораздо эффективнее или проще (при той же эффективности).
Ну, и последнее — нельзя заставить мэйстрим программировать чисто функциоально.
M>Причем числодробильные части (вроде парсера считанного файла и прочих строго алгоритмических замкнутых шагов) про Futures ничего знать не будут, это будет во внешнем (координирующем) коде.
Все так. Но числодробильные части — это обычно суровый императив. Возвращаясь к парсингу — быстрый парсер невозможен без оптимизаций вроде конечных автоматов с состоянием или таблиц мемоизации. Это все императив.
И от языка поддерживающего распараллеливание вычислений требуются гарантии, того что этот императив не станет причиной трудно уловимого бага.
Все что ты говоришь правильно и я это знаю. Но на практике, на большом проекте сделать хорошо распараллельненый код да еще и без блокировок крайне не просто. Ошибки все равно вылезают.
Людям свойственно ошибаться!
Задача языка — уберечь людей от ошибок или (хотя бы) сделать так, чтобы ошибки было легко выявить. Возможно поменять память из разных потоков — это гарантия, что ошибки будут.
Паттернами и библиотеками можно сократить их число. Но нельзя гарантировать их отсутствие или облегчить их выявление.
M>Локальные переменные
1. Зачастую дорого, так как приходится копировать тучу данных.
2. Опять же не гарантирует, что все изменения локальны. Локальная переменнамя может указывать на область памяти в которой будет изменяемое поле. И вот уже программист тратит неделю на поиск простейшего бага. А то и баг живет в продакшене много лет.
M>Immutable типы.
Опять же:
1. Дорого.
2. Это паттерн который легко нарушить и трудно найти его нарушение.
При этом мьютабельность в рамках одного потока совершенно безвредна.
VD>>Иными словами нужно сделать так, чтобы потоки не имели общих данных, а передача данных из одного потока в другой была прозрачной и дешевой. M>Не имели общих изменяемых данных.
Да. Сори. Исправил в своем сообщении.
M>Не вижу никаких проблем в неизменяемых данных, разделяемых многими потоками.
Проблема в неизменяемых данных одна — они не столь же универсальны как изменяемые. Нельзя сделать быструю сортировку или хэш-таблицу на неизменяемых данных. Хоть байт, но придется изменить. Плюс это зачастую дороже.
И чем больше объем данных, тем труднее удержать их неизменяемыми.
Ну, и повторюсь — это паттерн. А создать язык где все неизменяемо нельзя. Даже в Хаскеле есть лазейки. Плюс Хаскель дико не удобен в отладке и не все его могут использовать.
M>Передача незименяемых данных — простая и прозрачная.
Да. Но нет гарантии, что передаются только неизменяемые данные. Плюс дороговизна "изменения" неизменяемых структур (по сути их надо пересоздавать, хотя и возможно с и использованием большей части старых данных).
M>Чистота API (immutable in, immutable out) достигается ревью кода.
Ну тогда можно смело писать на С. Реьвю кода там доступен!
Такие вещи должны проверять компиляторы языков.
Если будет дешевое императивное изменение кучи данных и фича в языке позволяющее сказать, что отныне эти данных "заморожены", то проверять, что мы передали куда-то изменяемые данные просто не придется.
M>Внутри методов — пусть изменяемые структуры используют, не жалко.
А кто гарантирует, что где-то не осталось ссылочки на тот же объект и по ней параллельно что-то не будет изменено?
VD>>Нужно научить языки манипулировать кучами. Научить передавать эти кучи между "виртуальными процессами" (в стиле Эрланг). M>И программистов тоже этому учить?
Для программиста нужны простые и понятные конструкции вроде заморозки разморозки. А уж компилятор должен проверять, что потоку передаются замороженные данные и гарантировать, что два потока не получат возможность менять одну ячейку памяти.
На самом деле языки и сейчас оперируют весьма сложными вещами вроде GC, но программисты об этом и не думают. Вызвал new и получил объект. Точно так же и тут.
Возможно придется добавить какие-то дополнительные аннотации, но в целом это не должно быть сложно. Скажем нечто вроде оператора new с дополнительным параметром — кучей. В общем, как это оформить — надо думать. Ясно только что надо сделать.
M>А сколько там выиграть планируется по сравнению с futures+immutable structures?
Выиграть планируется — надежность.
А скорость будет обеспечиваться за счет выбора более производительных алгоритмов.
Скажем конечный автомат с доп памятью или мемоизация ускоряют парсинг нелинейно (устраняя возможную экспоненту). Ни один любитель ФП не вздумает писать быстрый парсер на неизменяемых структурах данных. Какой-нибудь Парсек сольет LR-автомату или Packrat-парсеру на первой же нетривиальной грамматике.
M>Я ради двух-трех раз в разнице производительности вряд ли буду учить новый язык и кучу вручную на области размечать.
Основное это надежность, как я уже говорил. Производительность она просто вытекает из надежности. Если ты гарантирован от ошибок, то можешь себе позволить по оптимизировать код. Если же сложность уже на грани, то ты вряд ли на это отчаешься.
M>За immutable плата есть, но относительно небольшая
Все зависит от задач. Скажем неизменяемое дерево и хэш-таблица имеют просто разную алгоритмическую сложность. По сему и решение на их основе будет отличаться по скорости. В парсерах я уже примеры приводил. В одном случае это будут оптимизированные алгоритмы, в другом будет приводить к экспоненте в некоторых случаях. Какие тут разы? Тут уже речь о непригодности.
M>(чуть менее оптимальные структуры, лишний lookup вместо циклов). Если припрет, я скорее будут смотреть на кластер по компиляции. Потому что в чистых функциях и ациклических графах выносить отдельные операции на кластер можно легко и просто.
Чистые функции и так параллелить нет проблем. Но вот писать только в чистых функйия на практике не выходит. Ну, или можно писать только некоторый класс задач.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Возможно придется добавить какие-то дополнительные аннотации, но в целом это не должно быть сложно. Скажем нечто вроде оператора new с дополнительным параметром — кучей. В общем, как это оформить — надо думать. Ясно только что надо сделать.
Давно всё придумано: Re: Мысли о эффективном автоматическом управлении памятью
VD>Все зависит от задач. Скажем неизменяемое дерево и хэш-таблица имеют просто разную алгоритмическую сложность. По сему и решение на их основе будет отличаться по скорости. В парсерах я уже примеры приводил. В одном случае это будут оптимизированные алгоритмы, в другом будет приводить к экспоненте в некоторых случаях. Какие тут разы? Тут уже речь о непригодности.
Тут всё не так плохо, как ты говоришь. Будет не экспонента, а умножение на Log(N) (возможно несколько раз) и большую константу.
Но всё равно результат обычно не укладывается в требования по производительности.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Я тебе уже отвечал, что это "придумано" на уровне того анекдота про переворачивающиеся на границе самолете. В реальности это не хилая инженерная задача, которая в процессе реализации почти наверняка даст совершенно не похожий на твои замысли результат. Точно так же как наши рассуждения о том какая должна быть Нитра 4 года назад мало напоминают то, что получилось в реальности.
Когда решаются технические проблемы всегда бывает легко и ясно когда ты к ним не приступил, и второе, когда ты закончил.
Твои "все давно придумано" это легкость и ясность "когда ты еще не приступал к решению задачи".
Вот на практике ты ведь знаешь, что надо в парсере поправить, чтобы он отступные грмматике парсил и одинаковые префиксы/постфиксы в правилах отслеживал. Скоро будет два года как ты это знаешь. И что? Почему ничего так и не реализовано?
WH>Тут всё не так плохо, как ты говоришь. Будет не экспонента, а умножение на Log(N) (возможно несколько раз) и большую константу.
Это если хотя бы дерево вместо хэш-таблицы использовать. Но по жизни в функциональном стиле пишут комбинаторные парсеры. Они очень красиво пишутся на разных Хаскелях. Но они в экспоненту выливаются. С таблицей мемоизации на базе дерева — да, экспоненты не будут. Будут просто тормоза. Но для практики и это не приемлемо.
Плюс опять же вопрос — как гарантировать, что все чисто функционально и неизменяемо? Еще на Хаскеле это можно обеспечить, но на мэйстрим-языках — нет.
WH>Но всё равно результат обычно не укладывается в требования по производительности.
+1
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Я тебе уже отвечал, что это "придумано" на уровне того анекдота про переворачивающиеся на границе самолете.
На уровне этого анегдота твоё:
Возможно придется добавить какие-то дополнительные аннотации, но в целом это не должно быть сложно. Скажем нечто вроде оператора new с дополнительным параметром — кучей. В общем, как это оформить — надо думать. Ясно только что надо сделать.
А там описан конкретный механизм.
С конкретной математикой.
Но ты его даже не пытался понять.
VD>Вот на практике ты ведь знаешь, что надо в парсере поправить, чтобы он отступные грмматике парсил и одинаковые префиксы/постфиксы в правилах отслеживал. Скоро будет два года как ты это знаешь. И что? Почему ничего так и не реализовано?
По тому что я эту задачу решать даже не начинал.
И тут это оффтопик.
VD>Это если хотя бы дерево вместо хэш-таблицы использовать. Но по жизни в функциональном стиле пишут комбинаторные парсеры. Они очень красиво пишутся на разных Хаскелях. Но они в экспоненту выливаются.
Это зависит от реализации. При желании на комбинаторах можно пакрат сделать.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>А там описан конкретный механизм.
А я тебе могу еще раз сказать, что все что там написано — это знание перед тем как сделать — т.е. ни о чем.
WH>С конкретной математикой.
Там треп, а не математика. Начнешь делать, сразу упрешься в реальность. Вся твоя математика пойдет в лес. Останутся только общие идеи.
WH>Но ты его даже не пытался понять.
Там понимать не чего. Там общие слова.
WH>По тому что я эту задачу решать даже не начинал.
Ну, да. Зато знаешь в деталях, как решать во много более сложные.
WH>И тут это оффтопик.
Ну, вот ты реши эту простую и конкретную задачу, в которой (казалось бы) известно как все делать. А потом рассказывай, обсудим что-то более сложное и отдаленное. А то то что нужно еще вчера и вроде как тоже ясно как решать у нас годами не делается, но мы обсуждаем как в деталях решать будущие задачи.
WH>Это зависит от реализации. При желании на комбинаторах можно пакрат сделать.
Может и можно, но не делают. В том же pappy, как я понимаю нормальную грамматику сделали, а комбинаторы в лес послали.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Там треп, а не математика. Начнешь делать, сразу упрешься в реальность. Вся твоя математика пойдет в лес. Останутся только общие идеи.
Трёп это у тебя. А там всё сводится к нескольким очень простым операциям.
WH>>По тому что я эту задачу решать даже не начинал. VD>Ну, да. Зато знаешь в деталях, как решать во много более сложные.
Намного более сложные задачи чем контроль графов объектов на этапе компиляции я уже успешно решал.
Восстановление после ошибок в нитре намного сложнее.
VD>Ну, вот ты реши эту простую и конкретную задачу, в которой (казалось бы) известно как все делать. А потом рассказывай, обсудим что-то более сложное и отдаленное. А то то что нужно еще вчера и вроде как тоже ясно как решать у нас годами не делается, но мы обсуждаем как в деталях решать будущие задачи.
Такие приёмы на мне даже в детском саду не работали.
Если тебе от меня что-то нужно попроси по нормальному.
VD>Может и можно, но не делают. В том же pappy, как я понимаю нормальную грамматику сделали, а комбинаторы в лес послали.
Вот например GLL'ные комбинаторы. https://github.com/djspiewak/gll-combinators/blob/master/examples/src/lambdacalc/LambdaCalcParser.scala
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Трёп это у тебя. А там всё сводится к нескольким очень простым операциям.
А, ну, тогда все ОК. Садись сделай.
WH>Намного более сложные задачи чем контроль графов объектов на этапе компиляции я уже успешно решал.
Ты когда начнешь решать, то поймешь, что это тоже сложная задача, а ты просто деталей не видел при взгляде из далека.
WH>Восстановление после ошибок в нитре намного сложнее.
Это ты после того как все трудности ощутил говоришь. А 3 года назад ни ты, ни я особых проблем не видели.
VD>>Ну, вот ты реши эту простую и конкретную задачу, в которой (казалось бы) известно как все делать. А потом рассказывай, обсудим что-то более сложное и отдаленное. А то то что нужно еще вчера и вроде как тоже ясно как решать у нас годами не делается, но мы обсуждаем как в деталях решать будущие задачи. WH>Такие приёмы на мне даже в детском саду не работали.
Какие приемы? Это факт. Реальная сложность задачи становится понятной только когда подходишь к реализации деталей. Вдруг оказывается масса внутренних противоречий и проблем. Но в теории, глядя на задачу абстрактно — все выглядит просто.
Вот только качественных реализаций ЖЦ можно по пальцам пересчитать.
WH>Если тебе от меня что-то нужно попроси по нормальному.
Я тебе 1.5 года назад сказал, что нам нужно. И уж если это сложно сделать, то шлушать как легко решать вселенские задачи создания эффективных и безопасных многопоточных языков мне уж совсем слушать смешно.
Если ты хочешь чтобы я тебе еще раз попросил, то ОК. Я гордый.
У нас в парсинге не сделаны следующие задачи:
1. Передача параметров в правила (с мемоизаций их значений). Это позволило бы решить следующие проблемы:
* Парсинг отступных грамматик (аля Хаскель).
* Парсинг правил с одинаковым префиксами и суфиксами (литералы С++, Раста, ХМЛ и т.п.).
2. Инкрементальный парсиг. Ты его почти сделал, но не доделал. А для качественной работы в редакторе это было бы очень желательно.
Если ты реально можешь это сделать, то сделай пожалуйста. Я полностью погряз в IDE-плагине. Да код этот твой. Ты в нем все знаешь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
WH>>Трёп это у тебя. А там всё сводится к нескольким очень простым операциям. VD>А, ну, тогда все ОК. Садись сделай.
Когда решу сделать язык обязательно сделаю.
VD>Ты когда начнешь решать, то поймешь, что это тоже сложная задача, а ты просто деталей не видел при взгляде из далека.
Нет там никаких деталей.
Всё что нужно это пометить каждый объект кучей, в которой он лежит.
После чего проконтролировать что ссылка на одну кучу не попала в объект другой кучи.
Тут справится тайпчекер каждого первого статически типизированного языка с генериками.
Сами кучи описываются через уникальные переменные.
Далее параметризируем типы переменными кучи и позволяем читать/писать только если соответствующая переменная жива.
Всё.
Подробности смотри по ссылкам. Я это всё между прочим для тебя написал.
Это всё мне очень напоминает историю с тем как ты мне доказывал, что у меня вставка в приоритетную очередь линейная. При этом даже не попытавшись понять алгоритм.
WH>>Такие приёмы на мне даже в детском саду не работали. VD>Какие приемы?
Взять на слабо.
Короче заканчивай с оффтопиком. Хочешь поговорить про нитру делай это в другом месте.
Тут обсуждается управление памятью.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, Khimik, Вы писали:
K>Сейчас вроде рост производительности процессоров остановился, значит будущее за распараллеливанием – много ядер, много процессоров в одном компьютере. Существуют ли ЯП, позволяющие удобно распараллелить алгоритм? Я это представляю так: в таких ЯП должны быть два типа циклов – обычные и параллельные. В обычных циклах есть какой-то счётчик, который увеличивается каждую итерацию, а в параллельных система должна сразу запустить много потоков, каждый из которых обрабатывает свой участок памяти и имеет на входе своё число – аналог счётчика. В этих параллельных циклах некоторые задачи будет невозможно реализовать – например, расчёт факториала. Но в целом, когда нужно будет в один присест обработать большой массив, они будут нормально работать.
Существует много всего. В своем комментарии ты описал OpenMP (расширение для С++). OpenMP позволяет решать такие задачи (это называется data parallel — когда каждый поток работает со своей независимой памятью, а потом все объединяется), но помимо этого, он позволяет задействовать task parallelism (это когда вычисление может быть представлено как ациклический направленный граф задач, т.е. стартует первая задача, порождает несколько новых, те порождают еще ряд задач и тд., расчет факториала или параллельный quicksort это как раз оно).
Помимо этого, есть еще такое расширение языка как Cilk (https://www.cilkplus.org/). Это тоже task level parallelism. Еще MIT недавно представили Milk (этот призван исправлять data access patterns в параллельных приложениях).
В принципе, все это можно делать на уровне библиотек (кроме того что делает Milk). Существуют высокоуровневые тулкиты, вроде Intel TBB, которые позволяют описывать топологию вычислений и запускать их. Futures/promises это по сути просто удобный интерфейс для реализации task parallelism-а. Для task level подхода достаточно иметь хорошую реализацию task pool-а (work stealing например). Вообще, одна из серьезных проблем обоих подходов (data parallel и task parallel — балансировка нагрузки, наивный подохд — разделить заранее все между потоками, работает только в простых случаях).
Еще можно посмотреть в сторону dataflow языков программирования, например StreamIt (на MIT open courseware есть серия лекций по параллельному программированию, в которых про него рассказывают). Примерно того же самого пытаются добиться с помощью библиотек, пример — http://www.raftlib.io/
Принцип, лежащий в основе dataflow подхода похож на task level подход. У нас тут тоже есть ациклический направленный граф каких-нибудь задач, вот только топология не incidential а строится заранее. Пример: мы пишем скан для СУБД, (упрощенно) скан перебирает блоки Б+дерева хранящиеся на диске, каждый блок должен быть прочитан, распакован, данные должны быть десериализованы, потом идет фильтрация (т.к. у нас есть where clause в запрсое), далее оно должно быть преобразовано в соответствии с projection в немного другую форму.
Data parallel подход тут работать не будет, так как scan должен обрабатывать данные в определенном порядке.
Task parallel как-то очень сложно и криво выглядит для этого случая.
Казалось бы тут нет параллелизма, но если все это реализовать с помощью RaftLib, то оно будет выполняться параллельно, будет построен конвейер, блоки будут читаться в буфер в одном потоке, второй поток будет брать блоки по очереди, распаковывать и передавать на десериализацию во второй поток (можно буферизовать данные между потоками, опять же), далее данные будут фильрроваться в еще одном потоке и тд. Количество потоков и распределение задач по потокам будет определяться библиотекой, например, если filter выполняется очень быстро то он не будет выноситься в отдельный поток а будет выполняться в том же потоке что и deserialization step для балансировки нагрузки.
Можно сделать то же самое для merge join-а двух деревьев:
Тут scan каждого дерева (таблицы) может быть распараллелен через конвейерную обработку, плюс возможно выполнять параллельное сканирование двух таблиц, плюс конвейерная обработка (сканирование) -> (kway merge) -> (output).
Здравствуйте, VladD2, Вы писали:
EP>>Это только для подмножества тех задач, в которых требуется передача данных между параллельными процессами. Многие же задачи выражаются через mapreduce, где внутри процессов нет никакого взаимодействия с другими.
VD>Это 100% задач. Все задачи требуют работы с данными. Мап-редью — не более чем алгоритм для определенных задач. Гарантий он никаких не дает. А для безопасного и производительного программирования нужны гарантии и контроль.
С помощью MapReduce считают page-rank например, ну и алгоритмы на графах тоже запускают как MapReduce задачи.
Про гарантии не очень понятно, гарантии отсутствия race conditions это хорошо, но это не гарантирует корректность параллельного алгоритма. Или ты хочешь научить компилятор доказывать корректность параллельных алгоритмов? Это похвально, желаю удачи (на самом деле), но не представляю как это может быть сделано. И еще такой момент, КМК ты не учитываешь одну вещь, помимо safety и correctness есть еще performance. Многие параллельные алгоритмы работают на одном ядре быстрее чем на двух или четырех и даже если это не так, там либо прирост проиходительности сублинеен, либо она начинает проседать когда мы запускаем это все на мультипроцессорной машине (внезапно, tradeoffs другие). Поэтому нужно учитывать не только thread safety но и memory access patterns и contention. Если все потоки юзают одну и ту же память на запись, то алгоритм перестает быть параллельным, так как исполнение сериализуется. В общем, не представляю как это все можно верифицировать автоматически.
Здравствуйте, VladD2, Вы писали:
VD>Эти библиотеки точно так же бесполезны. Они не более чем костыли не решающие проблему, а только лишь незначательно их облегчающие.
VD>В плане языковых средств и библиотек можно выделить такие либы как Rx и ReactiveUI. Это более полезные костыли. И там нет никаких циклов.
VD>Но даже эти продвинутые костыли не решают проблему конкурентного изменения данных.
VD>Для решения этой проблемы нужно делать новые языки и новые рантаймы к ним.
K>Сорри за профанство, но я не понимаю как этот код работает. Речь шла о том, что вычисление факториала как раз нельзя распараллелить.
Можно.
Разделяй и властвуй.
Один ицикл накопления факториала можно разбить на 2:
от 1 до n/2
от n/2 до n
Вот тебе и два треда...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Sharov, Вы писали:
S>Вот lock-free структуры данных эту проблему решают. Голова о синхронизации не болит.
Зуб дашь что у тебя в коде нигде нет доступа из разных потоков к данным которые к этому не готовы?
Чтобы можно было ответить да для кода из 1000+ строк нужен язык, который это контролирует.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Здравствуйте, Sharov, Вы писали:
S>>Вот lock-free структуры данных эту проблему решают. Голова о синхронизации не болит. WH>Зуб дашь что у тебя в коде нигде нет доступа из разных потоков к данным которые к этому не готовы? WH>Чтобы можно было ответить да для кода из 1000+ строк нужен язык, который это контролирует.
Если везде и всюду использовать типы из ConcurrentCollections, то зуб дам.
Здравствуйте, WolfHound, Вы писали:
S>>Вот lock-free структуры данных эту проблему решают. Голова о синхронизации не болит. WH>Зуб дашь что у тебя в коде нигде нет доступа из разных потоков к данным которые к этому не готовы? WH>Чтобы можно было ответить да для кода из 1000+ строк нужен язык, который это контролирует.
Не обязательно язык, и даже необязательно компилятор. Достаточно внешнего верификатора.
Здравствуйте, Sharov, Вы писали:
S>Вот lock-free структуры данных эту проблему решают. Голова о синхронизации не болит.
В общем случае ничего они не решают. Надо тебе две такие структуры изменить и гарантировать, что они синхронны в любой момент времени и ты приплы.
Я вот, кстати, недавно был вынужден заменить две лок-фри структуры на две доступных только для чтения и их заполнение под блокировкой. Это как бы совсем не в какие ворота.
Плюс повторяю еще раз, в надежде, что мысль дойдет. Главное, что нет никаких гарантий! Если среди гигабайта кода ты один раз ошибешься и воспользуеся не той структурой, не сделаешь блокировку или сделаешь ее не правильно, то компилятор тебя не остановит. Ошибку эту ты будешь ловит в рантайме и сделать это будет крайне не просто.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.