Я довольно хороший программист, мой начальник также довольно хороший программист. Хотя он, кажется, недооценивает некоторые задачи, такие как многопоточность, и насколько сложно это может быть (я нахожу это очень трудным для чего-то большего, чем запуск нескольких потоков, ожидание завершения всех, а затем возврата результатов).
В тот момент, когда вы начинаете беспокоиться о взаимоблокировках и условиях гонки, я нахожу это очень трудным, но босс, кажется, этого не ценит - я не думаю, что он когда-либо сталкивался с этим. Просто наденьте замок на это в значительной степени отношение.
Итак, как я могу представить его или объяснить, почему он может недооценивать сложности параллелизма, параллелизма и многопоточности? Или может я не прав?
Редактировать: немного о том, что он сделал - переберите список, для каждого элемента в этом списке создайте поток, который выполняет команду обновления базы данных на основе информации в этом элементе. Я не уверен, как он контролировал, сколько потоков выполнялось одновременно, я думаю, он, должно быть, добавил их в очередь, если их было слишком много (он не использовал бы семафор).
источник
Ответы:
Если вы можете рассчитывать на любой математический опыт, проиллюстрируйте, как обычный поток выполнения, который по существу является детерминированным, становится не просто недетерминированным с несколькими потоками, но экспоненциально сложным, потому что вы должны убедиться, что каждое возможное чередование машинных инструкций будет по-прежнему работать правильно. Простой пример потерянного обновления или грязного чтения часто открывает глаза.
«Забей на него» - тривиальное решение ... оно решает все твои проблемы, если ты не заботишься о производительности. Попытайтесь проиллюстрировать, какой удар по производительности был бы, если бы, например, Amazon пришлось блокировать все восточное побережье, когда кто-то в Атланте заказывает одну книгу!
источник
Многопоточность является простой. Кодирование приложения для многопоточности очень и очень просто.
Есть простой трюк, и это заключается в том, чтобы использовать хорошо спроектированную очередь сообщений ( не катите свою собственную) для передачи данных между потоками.
Трудная часть состоит в том, чтобы несколько потоков волшебным образом каким-то образом обновляли общий объект. Именно тогда это становится подверженным ошибкам, потому что люди не обращают внимания на условия гонки, которые присутствуют.
Многие люди не используют очереди сообщений и пытаются обновить общие объекты и создавать проблемы для себя.
Что становится трудным, так это разработка алгоритма, который хорошо работает при передаче данных между несколькими очередями. Это сложно Но механика сосуществующих потоков (через общие очереди) проста.
Также обратите внимание, что потоки совместно используют ресурсы ввода-вывода. Программа, связанная с вводом / выводом (т. Е. Сетевые соединения, файловые операции или операции с базой данных), вряд ли будет работать быстрее с большим количеством потоков.
Если вы хотите проиллюстрировать проблему обновления общего объекта, это просто. Сядьте через стол с кучей бумажных карточек. Запишите простой набор расчетов - 4 или 6 простых формул - с большим количеством места вниз по странице.
Вот игра. Каждый из вас читает формулу, пишет ответ и ставит карточку с ответом.
Каждый из вас сделает половину работы, верно? Вы сделали в половине случаев, верно?
Если ваш начальник не слишком много думает и только начинает, вы в некотором роде столкнетесь с конфликтом и будете писать ответы на одну и ту же формулу. Это не сработало, потому что между вами обоими читающими, прежде чем писать, есть неотъемлемое состояние гонки. Ничто не мешает вам читать одну и ту же формулу и переписывать ответы друг друга.
Существует много способов создать условия гонки с плохо или незапертыми ресурсами.
Если вы хотите избежать всех конфликтов, вы разрезаете бумагу на стопку формул. Вы берете один из очереди, записываете ответ и публикуете ответы. Нет конфликтов, потому что вы оба читаете из очереди сообщений только для одного читателя.
источник
Многопоточное программирование, вероятно, является наиболее сложным решением для параллелизма. По сути, это довольно низкий уровень абстракции того, что на самом деле делает машина.
Существует ряд подходов, таких как модель актора или (программная) транзакционная память , которые намного проще. Или работа с неизменяемыми структурами данных (такими как списки и деревья).
Как правило, правильное разделение задач облегчает многопоточность. Что-то, это все, что часто забывают, когда люди создают 20 потоков, все пытаются обработать один и тот же буфер. Используйте реакторы, где вам нужна синхронизация, и обычно передавайте данные между разными работниками с очередями сообщений.
Если у вас есть блокировка в логике приложения, вы сделали что-то не так.
Так что да, технически многопоточность сложна.
«Slap a lock on» - это в значительной степени наименее масштабируемое решение проблем параллелизма, которое фактически сводит на нет всю цель многопоточности. Что он делает, так это возвращает проблему обратно к неконкурентной модели выполнения. Чем больше вы это делаете, тем больше вероятность того, что у вас работает только один поток (или 0 в тупике). Это побеждает всю цель.
Это все равно, что сказать: «Решение проблем третьего мира легко. Просто бросьте в него бомбу». То, что существует тривиальное решение, не делает проблему тривиальной, поскольку вы заботитесь о качестве результата.
Но на практике решить эти проблемы так же сложно, как и любые другие проблемы программирования, и лучше всего делать это с помощью соответствующих абстракций. Что делает это довольно легко на самом деле.
источник
Я думаю, что у этого вопроса нет технической точки зрения - ИМО, это вопрос доверия. Нас обычно просят воспроизвести сложные приложения, такие как - о, я не знаю - например, Facebook. Я пришел к выводу, что если вам нужно объяснить сложность задачи непосвященному / руководству, то в Дании что-то гнилое.
Даже если другие программисты ниндзя смогут выполнить задачу за 5 минут, ваши оценки основаны на ваших личных способностях. Ваш собеседник должен либо научиться доверять вашему мнению по этому вопросу, либо нанять кого-то, чье слово они готовы принять.
Задача не в том, чтобы передать технические последствия, которые люди склонны игнорировать или не могут понять в ходе беседы, а в установлении отношений взаимного уважения.
источник
Один простой мысленный эксперимент для понимания тупиков - это проблема « столового философа ». Один из примеров, которые я склонен использовать для описания того, насколько плохими могут быть условия гонки, - это ситуация с Therac 25 .
«Просто бить по нему» - это менталитет того, кто не сталкивался с трудными ошибками с многопоточностью. И возможно, что он думает, что вы преувеличиваете серьезность ситуации (я не знаю - возможно взорвать вещи или убить людей с ошибками состояния гонки, особенно с помощью встроенного программного обеспечения, которое в конечном итоге оказывается в автомобилях).
источник
Параллельные приложения не являются детерминированными. С исключительно небольшим объемом всего кода, который программист признал уязвимым, вы не контролируете, когда часть потока / процесса выполняется по отношению к какой-либо части другого потока. Тестирование сложнее, занимает больше времени и вряд ли обнаружит все дефекты, связанные с параллелизмом. Дефекты, если они обнаружены, часто едва различимы, и их невозможно воспроизвести последовательно, поэтому их устранение затруднено.
Поэтому единственно правильное параллельное приложение - это то, которое доказуемо правильно, что не часто практикуется при разработке программного обеспечения. В результате ответ S.Lot является лучшим общим советом, так как передача сообщений относительно легко доказать, что это правильно.
источник
Краткий ответ в двух словах: НАБЛЮДАЕМЫЙ НОНДЕТЕРМИНИЗМ
Длинный ответ: это зависит от того, какой подход к параллельному программированию вы используете, учитывая вашу проблему. В книге « Концепции, методы и модели компьютерного программирования» авторы четко объясняют четыре основных практических подхода к написанию параллельных программ:
Теперь самым простым из этих четырех подходов, помимо очевидного последовательного программирования, является декларативный параллелизм , поскольку программы, написанные с использованием этого подхода, не имеют наблюдаемого недетерминизма . Другими словами, нет никаких условий гонки , поскольку состояние гонки - это просто наблюдаемое недетерминированное поведение.
Но отсутствие наблюдаемого недетерминизма означает, что есть некоторые проблемы, которые мы не можем решить, используя декларативный параллелизм. Здесь вступают в игру два последних не очень простых подхода. Не очень простая часть является следствием наблюдаемого недетерминизма. Теперь они оба подпадают под параллельную модель с сохранением состояния и также эквивалентны по выразительности. Но из-за постоянно растущего числа ядер на процессор, индустрия в последнее время проявляет все больший интерес к параллельности передачи сообщений, что можно увидеть в росте библиотек передачи сообщений (например, Akka для JVM) или языков программирования (например, Erlang ). ,
Ранее упомянутая библиотека Akka, опирающаяся на теоретическую модель Actor, упрощает создание параллельных приложений, поскольку вам больше не нужно иметь дело с блокировками, мониторами или транзакциями. С другой стороны, это требует другого подхода к разработке решения, то есть мышления с точки зрения того, как иерархически составлять участников. Можно сказать, что это требует совершенно другого мышления, которое, в конце концов, может оказаться еще сложнее, чем использование общего параллелизма в простом состоянии.
Параллельное программирование сложно из-за наблюдаемого недетерминизма, но при использовании правильного подхода к данной проблеме и правильной библиотеки, поддерживающей этот подход, можно избежать многих проблем.
источник
Сначала меня учили, что это может вызвать проблемы, увидев простую программу, которая запускает 2 потока и одновременно выводит их на консоль с 1 по 100. Вместо:
Вы получите что-то более похожее на это:
Запустите его снова, и вы можете получить совершенно другие результаты.
Большинство из нас были обучены предполагать, что наш код будет выполняться последовательно. С большинством многопоточности мы не можем принять это как должное "из коробки".
источник
Попробуйте использовать несколько молотков, чтобы растолочь кучу близко расположенных гвоздей, не связываясь между теми, кто держит молотки ... (предположим, что они с завязанными глазами).
Эскалируйте это к строительству дома.
Не спите по ночам, воображая, что вы архитектор. :)
источник
Простая часть: использование многопоточности с современными функциями сред, операционных систем и аппаратного обеспечения, таких как семафоры, очереди, блокированные счетчики, атомарные типы в штучной упаковке и т. Д.
Сложная часть: реализовать сами функции, не используя никаких функций, во-первых, может быть, за исключением нескольких очень ограниченных возможностей аппаратного обеспечения, полагаясь только на гарантии согласованности тактирования для нескольких ядер.
источник