Какова фактическая причина, по которой блокировки (часовые) в ОО трудно объяснить? [закрыто]

В этом разговоре Rich Hickey представляет Clojure. Он дает демо-версию Ants и рассказывает о своих мотивах для внедрения системы Transactional Memory (STM).

введите описание изображения здесь

Его аргументация для STM заключается в том, что "locks are hard to reason about".

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

Чтобы сделать эту работу на объектно-ориентированном языке, вам нужно либо использовать структуру STM, либо вручную вручную ее вручную.

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

Мой вопрос: Какова фактическая причина, по которой блокировки (часовые) в OO трудно обосновать?

6 голосов | спросил hawkeye 31 +03002014-10-31T13:40:39+03:00312014bEurope/MoscowFri, 31 Oct 2014 13:40:39 +0300 2014, 13:40:39

6 ответов


16

Это не имеет никакого отношения к OO в частности. Проблемы представляют собой проблемы с «явной блокировкой» парадигмы как подхода к параллелизму, независимо от других парадигм, используемых в других частях проблемы.

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

  • Замки не являются составными. Если у вас есть две части кода A и B, которые работают правильно (в частности, атомарно) самостоятельно, вы не можете писать A; B для выполнения двух действий вместе, atomically . По крайней мере, не обойтись без запирания замками A и B (которые часто являются частными, по уважительным причинам) или вводят еще один замок и вводят его повсюду, к которому его нужно придерживаться.

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

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

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

ответил 31 +03002014-10-31T14:55:10+03:00312014bEurope/MoscowFri, 31 Oct 2014 14:55:10 +0300 2014, 14:55:10
12

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

Единственная причина, по которой блокировка заставляет людей закручивать голову, заключается в том, что мы используем ее только в параллельных системах. Но представьте на мгновение, что у нас была очень параллельная система без синхронизации вообще; состояние системы со временем изменится на совершенно недействительные конфигурации. Многие из этих конфигураций так же трудно понять; они заставляют людей идти «Да? Как на Земле это могло случиться?» Причина в том, что мы не созданы, чтобы понять странное сочетание одновременных и чередующихся изменений, которые дают современные системы сокращения времени. Мало кто в реальной жизни работает таким образом, поэтому нашему мозгу очень тяжело.

ответил Kilian Foth 31 +03002014-10-31T13:57:39+03:00312014bEurope/MoscowFri, 31 Oct 2014 13:57:39 +0300 2014, 13:57:39
6

У меня нет опыта работы с STM, но я обращусь к блокирующей части.

Получение правильного кода с одним потоком затруднено. Это довольно говорит о том, что распространенная методология заключается в создании большой батареи модульных тестов и надеемся, что, если все пройдут, ничего не получается. Для кода, который не приведет к гибели людей или миллиардам долларов, это разумное приближение, но точка, которую я пытаюсь сделать, заключается в том, что правильный код proving правильный. Сложнее, чем большинство людей готовы приложить усилия.

Теперь рассмотрим параллельный код с помощью блокировок. Чтобы доказать, что это работает, вы должны доказать, что правильно синхронизировали потоки вручную для каждого возможного перемежения /планирования . Это монументальная задача. И если вы испортите, потому что код не детерминирован, поведение багги также не является детерминированным! Это не похоже на ручное управление памятью, за исключением того, что ресурсы отслеживания в однопоточном коде легче (но все же слишком сложно получить право).

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

Я не уверен, как OO вписывается в это. Блокировка на основе параллелизма жесткая, независимо от выбранной вами парадигмы.

ответил Doval 31 +03002014-10-31T14:52:42+03:00312014bEurope/MoscowFri, 31 Oct 2014 14:52:42 +0300 2014, 14:52:42
5

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

Если это делается путем выпирания замков прямо в объекты, то это почти всегда абсорбирование, из-за побочных эффектов, вызывающих блокировку.

  1. Если у вас есть много этих скрытых блокировок, то вряд ли вы столкнетесь с условиями гонки, но становится очень легко получить взаимоблокировки (которые, возможно, сами по себе являются просто условиями гонки, но я думаю, что вы получаете моя точка). Итак, вы должны рассуждать о порядке, в котором вы называете определенные методы, чтобы избежать взаимоблокировок. Нелегко рассуждать. И инкапсуляция, которую вы хотели просто, не существует.

  2. Или вы используете блокировки более редко, что упрощает устранение тупиков. Но также трудно рассуждать о том, где следует блокировать блокировки, чтобы избежать странного /неожиданного поведения. Это также означает, что вам слишком часто приходится тесно связывать реализацию объекта с при (в отличие от просто , как ) он будет сопряжен с внешним Мир. Таким образом, также нет реальной инкапсуляции.

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

ответил back2dos 31 +03002014-10-31T14:30:09+03:00312014bEurope/MoscowFri, 31 Oct 2014 14:30:09 +0300 2014, 14:30:09
4

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

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

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

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

И наши языки и системы типов не помогают справиться с этими задачами.

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

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

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

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

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

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

ответил Yakk 31 +03002014-10-31T21:16:59+03:00312014bEurope/MoscowFri, 31 Oct 2014 21:16:59 +0300 2014, 21:16:59
0

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

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

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

ответил zxq9 31 +03002014-10-31T19:49:12+03:00312014bEurope/MoscowFri, 31 Oct 2014 19:49:12 +0300 2014, 19:49:12

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132