Перейти к содержанию
Fire Monkey от А до Я
  • 0

Как правильно организовать многопоточный алгоритм


Alex7wrt

Вопрос

Добрый день.

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

Сама задача - расчёт столкновений шариков в двумерном пространстве. Цель - макс количество кадров в секунду.

Делал разными способами, но каждый раз получается не то, что нужно. 

Если в качестве синхронизации использовать TThread.OnTerminate, где по счетчику определять все ли потоки завершены и потом уже выводить на экран и создавать потоки заново, то получается очень медленно. 2 ядра дают 10% преимущества перед 1 ядром. Наверно потому что много времени уходит на создание потоков и ожидание выполнения всех.

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

И много промежуточных вариантов пробовал тоже.

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

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

потоки не могут ничего вывести на экран

рисует все равно только главный поток

здесь непонятен ваш алгоритм 

вы на каждый шарик запускаете отдельный поток? а потом ждете, пока все выполнятся?

Ссылка на комментарий
  • 0

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

Изменено пользователем Alex7wrt
Ссылка на комментарий
  • 0

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

Ссылка на комментарий
  • 0

А точно нужно дожидаться, пока все потоки отработают? Это не асинхронные задачи?

В качестве еще одного варианта - воспользуйтесь interlocked-функциями. Главный поток определяет, сколько вторичных потоков он запустит. И выставляет нужное значение в integer-переменной.

Каждый поток, завершив виток просчета вызывает InterlockedDecrement(ThreadCounter); При достижении нуля - из последнего вторичного потока вызывается TThread.Queue для сообщения главному потоку "все просчеты завершены". Ну и - потоки входят в спячку, например - на ожидании TEvent. А получив очередную порцию данных для просчета - выходят из ожидания события.

Даже лучше не так: каждый поток при запуске делает InterlockedIncrement(ThreadCounter), не стоит главному потоку выставлять начальное значение, хватит с него и запуска вторичных потоков. А вот всё остальное - да, остается в силе.

 

Изменено пользователем kami
Ссылка на комментарий
  • 0
20 часов назад, Alex7wrt сказал:

иначе приходится каждый раз после отрисовки создавать потоки заново

Если верить интернету, то в Windows создание потоков и синхронизация с основным потоком довольно "трудозатратая" операция. Для Windows я торможу поток dwStatus := WaitForSingleObject( Parms.fvEventUSB, INFINITE ); Когда надо запустить поток устанавливаю Event, данные из потока скидываю в потокобезопасный буффер и сообщаю об окончании обработки данных установкой другого Event.

Изменено пользователем GASCHE
Ссылка на комментарий
  • 0

насчет скорости создания потоков
 

procedure TfMain.RunThreads;
CONST MAX_THREADS=1000;
var
  i: Integer;
begin
  t1:=TThread.GetTickCount;
  threadCount:=MAX_THREADS;
  for i := 0 to MAX_THREADS-1 do
  begin
    TMyThread.Create(Handler).Start;
  end;
  t2:=TThread.GetTickCount;
  m1.Lines.Text := 'Запуск '+inttostr(MAX_THREADS)+': '+inttostr(t2-t1)+' мсек';
end;

{ TTMyThread }

constructor TMyThread.Create(AHandler: TNotifyEvent);
begin
  inherited Create(True);
  FreeOnTerminate := true;
  OnTerminate := AHandler;
end;

procedure TMyThread.Execute;
begin
  Sleep(5000);
end;

 

QIP Shot - Screen 116.png

Ссылка на комментарий
  • 0

имхо, с firemonkey неплохо работает такая схема:

1. создать две потокозащищенные очереди (структуры), на си для этого подходит std::deque, в fmx можно TList. Защита стандартно TCriticalSection;

2. создать несколько потоков, с помощью TEvent указать им ссылки на очереди и критические секции;

3. в потоках:

 3.1 TCriticalSection::Enter лочим очередь задач,

 3.2 забираем крайнюю задачу

 3.3 TCriticalSection::Leave отпускаем очередь задач

 3.4 вычисления

 3.5 по аналогии с очередью задач лочим очередь результатов, выкладываем результаты, отпускаем

 3.6 повтор с пункта 3.1

4. в основном потоке в очереди (тоже lock unlock) выкладывать задачи и при наличии результатов отрисовывать имеющимися средствами.

в 4 пункте нужен будет нужен будет какой-нибудь mmtimer.

 

Изменено пользователем Камышев Александр
Ссылка на комментарий
  • 0
  • Администраторы

Пулл потоков вам в помощь. Это о вопросе долго времени создания и удаления инстансов потоков.

Ссылка на комментарий
  • 0
В 28.05.2017 в 20:13, krapotkin сказал:

насчет скорости создания потоков

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

Кстати, судя по коду System.Threading - там как раз используется пул потоков. Они висят в ожидании "когда же нас озадачат" и после озадачивания - с радостным повизгиванием выполняют. Это к вопросу о

В 27.05.2017 в 21:33, Alex7wrt сказал:

возможно это подходит для "одноразовых задач"

 

Ссылка на комментарий
  • 0
5 часов назад, Brovin Yaroslav сказал:

Пулл потоков вам в помощь. Это о вопросе долго времени создания и удаления инстансов потоков.

Спасибо. А где можно почитать, как его использовать?

Ссылка на комментарий
  • 0
13 часа назад, Alex7wrt сказал:

Спасибо. А где можно почитать, как его использовать?

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

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...