Есть ли практические альтернативы темам? - PullRequest
12 голосов
/ 15 января 2010

Читая на SQLite, я наткнулся на эту цитату в FAQ: "Потоки злые. Избегайте их."

Я очень уважаю SQLite, поэтому я не мог просто игнорировать это. Я подумал, что еще я могу, согласно политике «избегать их», использовать вместо этого, чтобы распараллелить мои задачи. Например, приложение, над которым я сейчас работаю, требует пользовательского интерфейса, который всегда отзывчив и должен время от времени опрашивать несколько сайтов (процесс, который занимает не менее 30 секунд для каждого сайта).

Итак, я открыл PDF, связанный с этим FAQ, и, по сути, кажется, что в документе предлагается несколько методов , которые должны применяться вместе с потоками, такими как барьеры или транзакционная память, - а не какие-либо методы для замены все темы.

Учитывая, что эти методы не полностью обходятся без потоков (если я не неправильно понял, что говорится в документе), я вижу два варианта: либо FAQ по SQLite действительно не буквально означает то, что говорится, либо Существуют практические подходы, которые на самом деле избегают использования потоков в целом. Есть ли?


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

Ответы [ 12 ]

6 голосов
/ 17 января 2010

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


Я наконец дошел до чтения газеты. С чего начать?

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

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

Если вы не были уверены, что автор жил в академическом мире грез, вы можете быть уверены в этом после того, как он утверждает, что язык координации, который он предлагает в качестве альтернативы потокам, лучше всего можно выразить с помощью «визуального синтаксиса» (рисование графики на экране). Я никогда не слышал этого предложения раньше, кроме каждого года моей карьеры. Язык, которым можно манипулировать только с помощью графического интерфейса и который не работает ни с одним из обычных инструментов программиста, не является улучшением. Далее автор цитирует UML в качестве яркого примера визуального синтаксиса, который «обычно сочетается с C ++ и Java». Обычно в каком мире?

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

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

5 голосов
/ 15 января 2010

Утверждение в FAQ по SQLite, как я его прочитал, является просто комментарием о том, насколько трудной может быть многопоточность для непосвященных. Это мнение автора, и оно может быть верным. Но сказать, что вы никогда не должны использовать нитки, - значит выбросить ребенка с водой в ванне, на мой взгляд . Нитки - это инструмент. Как и все инструменты, их можно использовать и ими можно злоупотреблять. Я могу прочитать его статью и убедиться, что нити - это дьявол, но я успешно их использовал, без убийства котят.

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

Кроме того, SQLite не предназначен для использования в среде с высокой степенью одновременности. Если у вас есть один из них, вам лучше работать с более корпоративной базой данных, такой как Postgres.

2 голосов
/ 15 января 2010

Альтернативы темам:

  • сопрограмма
  • goroutines
  • MapReduce
  • workerpool
  • Великая центральная диспетчеризация яблока + лямбды
  • OpenCL
  • Эрл

(интересно отметить, что половина из этих технологий была изобретена или популяризирована Google.)

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

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

2 голосов
/ 15 января 2010

Программная транзакционная память ( STM ) - хороший альтернативный контроль параллелизма. Он хорошо масштабируется с несколькими процессорами и не имеет большинства проблем традиционных механизмов управления параллелизмом. Он реализован как часть языка Haskell . Стоит попробовать. Хотя я не знаю, как это применимо в контексте SQLite.

2 голосов
/ 15 января 2010

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

Взгляните на механизмы, используемые в Clojure (например, агенты , программная транзакционная память ).

2 голосов
/ 15 января 2010

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

  • Отличается зернистостью нарезания резьбы. Какао поддерживает все: от потоков posix (низкого уровня) до объектно-ориентированных потоков с NSLock и NSThread, до высокоуровневого пареллизма, например NSOperation. В зависимости от вашей задачи, использование высокоуровневого инструмента, такого как NSOperation, становится проще и выполняет свою работу.

  • Потоки за кулисами через API. Многие интерфейсы и анимация в какао скрыты за API. Вы несете ответственность за вызов метода API и предоставление асинхронного обратного вызова, который выполняется после завершения вторичного потока (например, конец некоторой анимации).

  • OpenMP. Существуют такие инструменты, как openMP, которые позволяют вам предоставлять прагмы, которые описывают компилятору, что некоторые задачи могут быть безопасно разбиты. Например, итерация набора элементов независимым способом.

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

2 голосов
/ 15 января 2010

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

Одна альтернатива - реализовать задачи, которые вы бы сделали в потоках, как конечные автоматы . По сути, задача делает то, что может сделать немедленно, затем переходит в свое следующее состояние, ожидая события, такого как поступление ввода в файл или отключение таймера. X Windows, как и большинство инструментов GUI, поддерживают этот стиль. Когда что-то происходит, они вызывают обратный вызов, который делает то, что ему нужно, и возвращает. Для FSM обратный вызов проверяет, в каком состоянии находится задача и что это за событие, чтобы определить, что делать немедленно и каким будет следующее состояние.

Допустим, у вас есть приложение, которое должно принимать сокетные соединения, и для каждого соединения анализировать командные строки, выполнять некоторый код и возвращать результаты. Задачей будет то, что слушает сокет. Когда select() (или Gtk +, или что-то еще) говорит вам, что сокету есть что читать, вы читаете это в буфер, затем проверяете, достаточно ли у вас буферизованного ввода для чего-либо. Если это так, вы переходите в состояние «начать делать что-то», в противном случае вы остаетесь в состоянии «чтение строки». (То, что вы «делаете», может быть несколькими состояниями.) По завершении ваша задача удаляет строку из буфера и возвращается в состояние «чтение строки». Нет необходимости в потоках или вытеснении.

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

P.S. Другой способ получить потоки без реального использования потоков - это библиотека GNU Pth . Это не делает вытеснение, но это еще один вариант, если вы действительно не хотите иметь дело с потоками.

2 голосов
/ 15 января 2010

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

1 голос
/ 15 января 2010

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

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

1 голос
/ 15 января 2010

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

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

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

Это действительно вопрос применения. Если ваша задача достаточно проста, чтобы вписаться в какой-либо высокоуровневый объект задачи (зависит от вашей платформы разработки; ваш пробег может варьироваться), то лучше всего использовать очередь задач. Мое эмпирическое правило таково: если вы не можете найти классное имя для своего потока, то его задача не настолько важна, чтобы оправдать поток (вместо задачи, идущей в очередь операций).

...