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

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

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

  1. Класс TThread в Delphi

  2. AsyncCalls by Andreas Hausladen

  3. OmniThreadLibrary от Primoz Gabrijelcic (gabr)

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


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

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

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

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

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

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

, 4. Прямые вызовы в Windows API

, 5. Распределенная прикладная структура CSI Misha Charrett, предложенная LachlanG в его ответе.


Вывод:

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

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

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

Использование простого classа оболочки streamов в основном также заставляет разработчика сосредоточиться на слишком низком уровне. Для правильного использования нескольких ядер процессора лучше сосредоточиться на задачах вместо streamов, потому что разделение работы с streamами плохо адаптируется к изменяющимся требованиям и средам – ​​в зависимости от аппаратного и другого программного обеспечения, работающего параллельно, оптимальное количество streamи могут сильно различаться, даже в разное время в одной и той же системе. Библиотека, в которую вы передаете только куски работы, и которая автоматически их расписала, чтобы наилучшим образом использовать доступные ресурсы, очень помогает в этом отношении.

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

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

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

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

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

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

Существует еще одна менее известная библиотека streamов Delphi, платформа приложений CSI от Misha Charrett.

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

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

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

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

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

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

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

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

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

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

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

Я знаю, что это не самый продвинутый метод :-), и, возможно, у него тоже есть ограничения, но я просто попробовал System. BeginThread и нашел это довольно простым – возможно, из-за качества документации, о которой я говорил … http://www.delphibasics.co.uk/RTL.asp?Name=BeginThread (ИМО Нейл Моффатт мог научить MSDN или два)

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

EDIT на самом деле Роб Кеннеди делает отличную работу, объясняя BeginThread здесь BeginThread Structure – Delphi

EDIT на самом деле, как Роб Кеннеди объясняет TThread в том же сообщении, я думаю, что я изменю свой код, чтобы использовать TThread tommorrow. Кто знает, как это будет выглядеть на следующей неделе! (Возможно, AsyncCalls)

  • В чем разница между асинхронным программированием и многоstreamовой обработкой?
  • Секвенирование и реорганизация задач
  • Почему setState в реале Async вместо Sync?
  • Запуск нескольких задач async и ожидание их завершения
  • Лучший способ в .NET управлять очередью задач на отдельном (одном) streamе
  • asynchronous и неблокирующий
  • Подождите, пока быстрый цикл цикла с асинхронными сетевыми запросами завершит выполнение
  • ожидаемая очередь на основе задач
  • Wait Firebase async извлекает данные на Android
  • В чем разница между возвратом пустоты и возвратом задачи?
  • Как создать streamи в nodejs
  • Давайте будем гением компьютера.