Как выбрать между различными способами создания потоков в Delphi?

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

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

  1. Класс TThread в Delphi

  2. AsyncCalls Автор Андреас Хаусладен

  3. ] OmniThreadLibrary Примоз Габриэльчич (габр)

  4. ... любые другие?


Редактировать:

Я только что прочитал отличную статью Габра в мартовском выпуске № 10 (№ 10) Blaise Pascal Magazine под названием «Четыре способа создать тему». Вы должны подписаться, чтобы получать контент для журнала, поэтому по закону об авторских правах я не могу воспроизвести здесь что-либо существенное об этом.

В заключение, Габр описывает разницу между использованием TThreads, прямыми вызовами API Windows, AsyncCalls Энди и его собственная библиотека OmniThread. В конце он приходит к выводу:

«Я не говорю, что вам нужно выбирать что-то еще, кроме классического способа Дельфи (TThread), но все же хорошо знать, какие у вас есть варианты»

Ответ Мги очень тщательно и предполагает, что OmniThreadLibrary может быть предпочтительнее. Но я все еще интересуюсь мнением каждого о том, как я (или кто-либо другой) должен выбрать метод их потоков для своего приложения.

И вы можете добавить в список:

. 4. Прямые звонки в Windows API

. 5. Миша Чарретт s CSI Distributed Application Framework , как было предложено LachlanG в его ответе.


Заключение:

Я, вероятно, пойду с OmniThreadLibrary. Мне нравится работа Габра. Я использовал его профилировщик GPProfile много лет назад, и в настоящее время я использую его GPStringHash, который на самом деле является частью OTL.

Моя единственная задача - обновить его для работы с 64-битной или Unix / Mac обработкой, как только Embarcadero добавляет эту функциональность. в Дельфы.

63
задан Community 23 May 2017 в 11:33
поделиться

4 ответа

Если у вас нет опыта работы с многопоточностью, вам, вероятно, не следует начинать с TThread , поскольку это всего лишь тонкий слой по сравнению с естественной потоковой передачей. Я считаю, что это также немного грубовато по краям; он не претерпел значительных изменений с момента появления Delphi 2, в основном это изменения для обеспечения совместимости с Linux во временных рамках Kylix и для исправления более очевидных дефектов (например, исправление неработающего класса MREW и, наконец, отказ от Suspend () и Resume () в последней версии Delphi).

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

AsyncCalls - хороший первый шаг для внедрения потоков в приложение.Если у вас есть несколько областей в вашей программе, где необходимо выполнить ряд трудоемких шагов, независимых друг от друга, вы можете просто выполнить их асинхронно, передав каждую из них в AsyncCalls. Даже если у вас есть только одно такое трудоемкое действие, вы можете выполнить его асинхронно и просто показать пользовательский интерфейс выполнения в потоке VCL, при необходимости позволяя отменить действие.

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

Что вам также нужно знать, так это то, что эти асинхронные действия не типа «запустил и забыл». Каждая перегруженная функция AsyncCall () возвращает указатель интерфейса IAsyncCall , на который вам может понадобиться сохранить ссылку, если вы хотите избежать блокировки. Если вы не сохраните ссылку, то в тот момент, когда счетчик ссылок достигнет нуля, интерфейс будет освобожден, что приведет к тому, что поток, освобождающий интерфейс, будет ждать завершения асинхронного вызова. Это то, что вы можете увидеть во время отладки, когда выход из метода, создавшего IAsyncCall , может занять загадочное количество времени.

OTL, на мой взгляд, является наиболее универсальным из ваших трех вариантов, и я бы использовал его, не задумываясь. Он может делать все, что TThread и AsyncCalls, а также многое другое.Он имеет продуманный дизайн, достаточно высокоуровневый, чтобы упростить жизнь пользователю и позволить переносу на систему Unixy (при сохранении большей части интерфейса нетронутой) выглядеть по крайней мере возможным, если не простым. В последние месяцы он также начал приобретать некоторые высокоуровневые конструкции для параллельной работы, что очень рекомендуется.

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

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

43
ответ дан 24 November 2019 в 16:28
поделиться

TThread - это простой класс, который инкапсулирует поток Windows. Вы создаете класс-потомок с методом Execute, который содержит код, который этот поток должен выполнять, создаете поток и устанавливаете его для запуска, а код выполняется.

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

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

6
ответ дан 24 November 2019 в 16:28
поделиться

Существует еще одна менее известная библиотека потоков Delphi, CSI Application Framework Миши Чарретта.

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

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

Миша разрабатывал это в течение многих лет и до сих пор активно улучшает структуру и документацию. Он всегда очень отзывчив к вопросам поддержки.

7
ответ дан 24 November 2019 в 16:28
поделиться

(извините, у меня недостаточно очков для комментариев, поэтому я помещаю это как ответ, а не еще одно голосование за OTL)

Я использовал TThread, CSI и OmniThread (OTL). Обе библиотеки имеют нетривиальные кривые обучения, но они гораздо более эффективны, чем TThread. Я пришел к выводу, что если вы собираетесь сделать что-нибудь существенное с потоковой передачей, вы все равно напишете половину функциональности библиотеки, так что вы можете также начать с рабочей, отлаженной версии, написанной кем-то другим. И Миша, и Габр - лучшие программисты, чем большинство из нас, так что велика вероятность, что они сделали работу лучше, чем мы.

Я просмотрел AsyncCalls, но он не дал достаточно того, что я хотел. Одна вещь, которую он имеет, - это функция "Synchronize" (отсутствует в OTL), поэтому, если вы зависим от нее, вы можете использовать AynscCalls исключительно для этого. IMO с использованием передачи сообщений недостаточно сложно, чтобы оправдать неприятность Synchronize, поэтому пристегнитесь и научитесь использовать сообщения.

Из трех я предпочитаю OTL, в основном из-за набора примеров, но также и потому, что он более самодостаточен. Это меньшая проблема, если вы уже используете JCL или работаете только в одном месте, но я делаю сочетание, включающее контрактную работу и продажу клиентов при установке системы Миши, сложнее, чем OTL, просто потому, что OTL составляет ~ 20 файлов. в одном каталоге. Звучит глупо, но для многих это важно.

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

6
ответ дан 24 November 2019 в 16:28
поделиться
Другие вопросы по тегам:

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