понедельник, 13 января 2025 г.

[prog.c++] Интересная постановка вопроса: если люди испытывают сложности с многопоточностью, то не забанить ли многопоточность совсем?

Этот вопрос всплыл на днях на r/cpp. Позволю себе процитировать значимую часть поста с reddit-а без перевода:

Hi all,

Had an interesting discussion today and would appreciate some advice.

Multithreaded code can be especially tricky for medium to junior level developers to write correctly. When a mistake is made, it can result in difficult to find bugs.

If the application you are working on needs to be very reliable (but isn't safety critical), what would you recommend for medium/low experience c++ teams?

Assume that the application will need to do 4 things at once and can't use state machines or coroutines. The various "threads" need to regularly exchange less than 10 KB of data a second.

Do you ban threads?

A few approaches come to mind.

#1 train the team to know the dangers and let them use threads with best practices. More experienced (and paranoid/diligent) developers carefully audit.

Any suggestions for books/resources for this team?

#2 and/or use a tool or technique to detect concurrency issues at compile time or during test? Thread sanitizer? cppcheck? ???

#3 ban threads and force concurrency to be implemented with multiple processes. 4 processes each with 1 thread. The processes will communicate with some form of IPC.

Т.е. смысл в том, что для разработчиков уровня middle/junior написание мультипоточного кода зачастую оказывается слишком сложным. И если приложение должно быть надежным, то возникает вопрос: как же быть? Может быть проще вообще запретить многопоточность в пользу многопроцессности? А если не запрещать, то что? Учить людей? Использовать какие-то инструменты для тестирования и анализа корректности кода?

Признаться, комментарии на reddit-е к этому посту я не читал, только просмотрел мельком и не увидел того, чего хотел 🙁

Поэтому выражу эмоции в этом блог-посте.

Хватить себя обманывать -- писать низкоуровневый многопоточный код сложно не только middle/junior-ам, но и senior-ам. Не устану повторять, что многопоточность на голых нитях, mutex-ах, condition_variable и, ниприведихоспади, atomic-ах -- это пот, боль и кровь.

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

Однако, такая рекомендация звучит очень похоже на банальность вида "хочешь быть здоровым -- будь им". Столь же бесполезная.

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

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

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

Ну а раз не обойтись, что вопрос уже не в том, запрещать многопоточность или нет. Вопрос в том, как уменьшить количество головной боли при использовании многопоточности. И ответ на него достаточно простой: использовать инструменты уровнем повыше, чем голые нити и примитивы синхронизации. Акторы, сопрограммы, CSP-шные каналы, task-и и вот это вот все. Плюс идеология shared nothing во главе угла (в том смысле, что чем меньше у вас разделяемых мутабельных данных, тем меньше у вас проблем).

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

Конечно же, ни акторы, ни CSP, ни task-и не избавляют нас от абсолютно всех проблем, и у этих подходов так же есть свои подводные камни. Тем не менее, многопоточность на акторах или CSP-шных каналах гораздо проще и безопаснее. Многократно проверено на людях.


Выбор между многопоточностью и многопроцессностью в современных условиях, имхо, должен лежать не плоскости простоты написания многопоточного или однопоточного кода. А, прежде всего, в плоскости дополнительных факторов. Например, таких как:

  • обеспечение надежности работы в условиях ненадежности используемых программных компонент. Например, мы вынуждены полагаться на стороннюю библиотеку, которая время от времени падает и роняет весь процесс, в котором ее используют. Библиотека не наша, мы не можем "довести ее до ума", можем только минимизировать причиняемый ею ущерб;
  • обеспечение надежности работы в условиях ненадежности внешнего оборудования и/или внешних сервисов. Например, к компьютеру подключено устройство, которое может зависнуть. И единственный способ вернуть его к жизни -- это убить процесс, который общался с устройством, переинициалировать устройство и начать работать с ним заново. Аналогично и со сторонними сервисами, с которыми мы можем общаться через HTTP(S) или еще какую-то форму IPC. Бывает, что такой сервис набирает от нас N запросов и перестает подавать признаки жизни до тех пор, пока все эти N запросов не будут принудительно прекращены;
  • возможность жесткого прерывания длительных операций. Например, какой-то математический расчет, который может занимать часы и который не так-то просто прервать "изнутри". Но вот если вынести этот расчет в отдельный процесс, то этот процесс легко "прибить" в случае необходимости;
  • простота и удобство реконфигурации "на лету". Иногда работающий в режиме 24/7 сервис нужно переконфигурировать без его останова, но из-за внутренней кухни и/или особенностей использованных в нем библиотек, сделать такую переконфигурацию затруднительно.

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

  • в Unix-ах нужно избегать возникновения зомби-процессов;
  • после принудительно убитого дочернего процесса могут оставаться различные следы жизнедеятельности (в виде .tmp-файлов, которые не были вовремя удалены), которые нужно подчищать;
  • если взаимодействие идет через shared-memory, то нужно как-то определить а доверяем ли мы текущему содержимому блока разделяемой памяти или же внезапно умерший дочерний процесс оставил там какой-то мусор...

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

Но аргументы "за" такой переход точно не должны быть из категории "однопоточное программирование проще многопоточного".


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

суббота, 4 января 2025 г.

[life.books] Кратко о книге "Ковчег 47 Либра"

Когда-то давно, году в 2005-ом или 2006-ом прочитал отличный научно-фантастический роман "Стая" Франка Шетцинга. Сильно тогда впечатлился. Ощущения были как будто в детстве читаешь произведения Жюля Верна, где фантастические события базируются на научной основе.

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

Однако, несколько месяцев назад почему-то захотелось перечитать "Стаю". Ни с того, ни с сего.

Нашел, перечитал. Впечатление, конечно же, не такое яркое, но все равно получил удовольствие.

Внезапно возникло желание прочесть еще что-нибудь из фантастики. Но что именно?

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

А тут как-то случайно через ролики на YouTube узнал о существовании Бориса Евгеньевича Штерна. И о том, что он пишет научную фантастику. Решил попробовать что-то из его произведений прочитать. Наугад попал в "Ковчег 47 Либра". И не смог остановиться.

Вот прям такое же ощущение, как в детстве, когда читаешь жюльверновские "20 тысяч лье под водой" или "Таинственный остров".

Мне отлично зашло. Настолько, что захотелось оставить зарубку в склерознике.

четверг, 2 января 2025 г.

[life.cinema] Очередной кинообзор (2024/12)

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

Фильмы

Веном: Последний танец (Venom: The Last Dance, 2024). Третья часть мне понравилась больше, чем вторая. Хотя есть ощущение, что фильм полностью держится на юморе + еще немного на хорошей графике. Тем не менее, как аттракцион, который позволяет отвлечься от повседневных забот, фильм отличный.

Блуждающая тень (The Shadow Strays, 2024). Отличное кино для любителей жанра "кровавое мочилово". Хотя, имхо, до уровня первого "Рейда" чутка не дотянули, но очень старались.

День Шакала (The Day of the Jackal, 1973). Посмотрел его после одноименного сериала 2024-го года. Общего не так уж много, так что можно смотреть практически как самостоятельное произведение. Полагаю, что для своего времени было отличное кино, но сейчас это совсем уж ретро.

Задержанная (Detained, 2024). Средней паршивости кино. Производит впечатление телеспектакля, а не художественного фильма. Можно глянуть, если больше вообще уже нечего смотреть.

Безмолвное братство (The Order, 2024). Наглядный пример того, как потенциально интересную историю превратить в унылое говно.

Ручная кладь (Carry-On, 2024). Откровенная халтура. Причем и как по сюжету, так и по исполнению.

Сериалы

День шакала (The Day of the Jackal, первый сезон, 2024). К происходившему на экране есть несколько серьезных вопросов, но в целом понравился. Возможно, это лучший сериал из увиденных в 2024-ом году.

Чужак (The Outsider, 2020). О просмотре не жалею, но и не впечатлил. Сделано добротно. Но, имхо, можно было бы на пару серий и подсократить.

Горький 53 (первый сезон, 2024). Есть ощущение, что съемки этого сериала организовали чтобы пристроить большое количество известных еще 10-15 лет назад хороших актеров. Видеть их приятно, они стараются и мастерства у каждого на десятерых, но общее впечатление от сериала средненькое. Слишком много вопросов к сюжету, а развязка оставляет вопрос "И это все?" Может быть создатели планируют продолжение?

Боевой ангел (Machine, первый сезон, 2024). Все очень простенько, наивно, прямолинейно и предсказуемо. Но в этом есть свое очарование. Так что лично мне вполне зашел как раз потому, что можно не вдумываться в происходящее. Еще бы экшОна с мордобоем бы побольше, зашел бы еще лучше :)

Вне категории

Присяжный номер два (Juror #2, 2024). У меня просто нет цензурный слов: что бы так слить собственный фильм в унитаз Клинту Иствуду нужно было сильно постараться. Вот зачем нужно было историю главного героя раскрывать в самом начале? Это же убило всю интригу. Мне совершенно непонятно. Расскажи судьбу Джастина Кемпа в финале картины и получилось бы совсем другое кино, гораздо более интересное и с неожиданным поворотом в развязке.