Максимальное разумное количество работающих потоков .

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Максимальное разумное количество работающих потоков .

Сообщение Alex2013 » 13.04.2025 22:34:55

Все три фазы в многопоточном режиме !
Код: Выделить всё
Тест загрузки списка 3
MT Mode Попытки 1
Время 0,38 c
Время 0,44 c
Время 1,29 c


Для сравнения "Однопоточный режим"
Код: Выделить всё
Тест загрузки списка 3
Время 0,86 c
Время 0,93 c
Время 3,54 c

(Правда сделал "по своему" и в последней фазе немного схитрил (отказался от ожидания) так что крайний "рекорд"(общее время загрузки 30-ти картинок 1,29 c ) малость сомнительный (общее время "с ожиданием" примерно тоже что и у однопоточного режима отличия в пределах погрешности измерений ) ) Но тем не менее небольшой выигрыш есть . (впрочем это касается именно "трёхфазной " загрузки сравнения с "однофазными" заметно веселее )

Код: Выделить всё
Тест загрузки списка 2
Однопоточный
Время 10,63 c i 29 c 30 
Тест загрузки списка 2
Многопоточный
Время 8,58 c i 28 c 30 

(Если увеличить количество потоков результат будет лучше но ценой заметного тормоза программы и всей системы )

Малый "стресс тест " ( 84 файла)
Код: Выделить всё
Тест загрузки списка 3
MT Mode Попытки 1
Время 0,08 c
Время 0,22 c
Время 10,14 c
Тест загрузки списка 2
Многопоточный
Время 22,15 c  84 ф
(Большой стресс-тест "MT Mode 3.0" пока не проходит (но думаю я знаю причину - нет запуска потоков " по частям" (как это уже сделано в "MT Mode 2.0"))
Последний раз редактировалось Alex2013 17.04.2025 23:19:49, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 3124
Зарегистрирован: 03.04.2013 11:59:44

Re: Максимальное разумное количество работающих потоков .

Сообщение sts » 15.04.2025 14:19:13

надо еще проверить файлмаппинг на память, самый быстрый доступ к содержимому файла
sts
постоялец
 
Сообщения: 451
Зарегистрирован: 04.04.2008 12:15:44
Откуда: Тольятти

Re: Максимальное разумное количество работающих потоков .

Сообщение Alex2013 » 17.04.2025 22:51:31

sts писал(а):надо еще проверить файлмаппинг на память, самый быстрый доступ к содержимому файла

Это мысль ! :idea:
Но у меня сейчас "красивая теория убита безобразным опытом" ...
Там где "трехфазный" однопоточный код "работает как часы" многопоточный упирается рогом на всех трех фазах.
(Поочереди отключал МП-режим для каждой но "большой стресс-тест" (около гигабайта файлов) убивает все )
И органичнее количества активных потоков к сожалению не помогает...
Зы
"Спросил у ясеня" (тобишь у ИИ ) и он предсказуемо "забросал листвой"...
Но кое-что полезное точно есть, например мануал по завершению "зависших" потоков.
Код: Выделить всё
Как безопасно завершить "повисший" поток в Lazarus/Free Pascal
Завершение зависшего потока — сложная задача, потому что принудительное убийство (TerminateThread) может привести к утечкам памяти, повреждению данных или непредсказуемым ошибкам.
Но есть безопасные стратегии для корректного завершения:

1. Мягкое завершение (рекомендуется)
Использование Terminate + проверка флага в потоке
Поток должен регулярно проверять Terminated и завершаться сам.
Пример:
pascal
Copy
type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TMyThread.Execute;
begin
  while not Terminated do // Проверяем флаг завершения
  begin
    // Рабочий код...
    if SomeCondition then Break; // Выход по условию
    Sleep(10); // Даём потоку "передышку"
  end;
end;
Как завершить:
pascal
Copy
MyThread.Terminate;  // Устанавливает флаг Terminated
MyThread.WaitFor;    // Ждём завершения (можно с таймаутом)
Плюсы:
? Безопасно
? Нет утечек ресурсов
Минусы:
? Если поток "завис" в внешнем вызове (например, HTTP-запрос), флаг Terminated не поможет.

2. Принудительное завершение (опасно, но иногда необходимо)
Вариант 1: TerminateThread (Windows API)
pascal
Copy
uses
  Windows;

// ОПАСНО! Может вызвать утечки памяти.
TerminateThread(MyThread.Handle, 0);
Проблемы:
    • Может оставить заблокированные мьютексы/критические секции.
    • Не освобождает память и хендлы.
Вариант 2: Через TThread.FreeOnTerminate
Если поток завершится аварийно, но FreeOnTerminate := True, он автоматически уничтожится.
pascal
Copy
MyThread.FreeOnTerminate := True;
MyThread.Terminate;
Но: Это не гарантирует немедленного завершения.

3. Гибридный подход (таймаут + принудительное завершение)
Шаг 1: Мягкое завершение (Terminate + WaitFor)
pascal
Copy
MyThread.Terminate;
if MyThread.WaitFor(5000) = wrTimeout then // Ждём 5 сек
begin
  // Поток не ответил, завершаем принудительно
  TerminateThread(MyThread.Handle, 0);
  MyThread.Free;
end;
Шаг 2: Защита ресурсов
Если поток использует критические секции, файлы или соединения, добавьте try..finally:
pascal
Copy
procedure TMyThread.Execute;
begin
  try
    while not Terminated do
    begin
      // Код...
    end;
  finally
    CloseHandle(SomeResource); // Освобождаем ресурсы
  end;
end;

4. Альтернатива: Изоляция потоков (лучшая практика)
Если поток выполняет HTTP-запросы, чтение файлов или другие долгие операции, вынесите их в отдельный процесс (например, через TProcess).
pascal
Copy
uses
  Process;

var
  Proc: TProcess;
begin
  Proc := TProcess.Create(nil);
  try
    Proc.Executable := 'my_helper_tool.exe';
    Proc.Options := [poNoConsole];
    Proc.Execute;
   
    // Ждём завершения с таймаутом
    if Proc.WaitForExit(5000) then
      Memo1.Lines.Add('Успешно завершено')
    else
    begin
      Proc.Terminate(0); // SIGTERM (мягкое завершение)
      Sleep(1000);
      if Proc.Running then
        Proc.Kill(1);    // SIGKILL (принудительное)
    end;
  finally
    Proc.Free;
  end;
end;
Плюсы:
✔ Процессы изолированы, краш одного не влияет на основной поток.
✔ Можно убить без утечек в основном приложении.

Итоговые рекомендации

Код: Выделить всё
Способ                   Безопасность          Применимость
----------------------------------------------------------------------------------------
Terminate + WaitFor   ✅ Высокая             Лучший вариант для чистого кода
TerminateThread       ❌ Опасен              Только в крайних случаях!
Изоляция в TProcess   ✅ Максимальная        Для HTTP/долгих операций


Лучший вариант:
1. Проверяйте Terminated в потоке в долгих циклах.
2. Используйте WaitFor с таймаутом.
3. Если поток не отвечает – попробуйте закрыть его ресурсы и только потом TerminateThread.
4. Для HTTP/опасных операций – выносите в TProcess. Если сделаете так, зависание потоков будет минимальным!

Краткий чек-лист для безопасного завершения потоков
1. Всегда проверяйте Terminated в долгих операциях.
2. Используйте WaitFor(таймаут) вместо бесконечного ожидания.
3. Закрывайте ресурсы (файлы, соединения) в finally.
4. Избегайте TerminateThread — только если поток реально завис и не реагирует.
5. Для HTTP/опасных задач — лучше TProcess.
Alex2013
долгожитель
 
Сообщения: 3124
Зарегистрирован: 03.04.2013 11:59:44

Re: Максимальное разумное количество работающих потоков .

Сообщение Alex2013 » 19.04.2025 09:33:17

Баг победил... Но есть одна беда "победил" перебором вариантов... и главное не понял почему я его победили ...
1 Более мнение понятно Оказалось что нужно ограничивать количество СОЗДАННЫХ но незпущенных потоков. (Хотя странно, по идее созданный но незапущенный поток просто обычный объект/класс в памяти )
2 Непонятно совсем.
Если передача параметров происходит через конструктор все в порядке, а если конструктор создает поток в остановленном состоянии и я просто записываю данные прямо в поля потока, а потом запускаю нет. (Причем "глюки" идут какие-то "плавающие" то работает то нет )

ЗЫ
При этом если создавать поток в остановленном состоянии, и сразу запускать БЕЗ "ПРЯМОЙ" ПЕРЕДАЧИ ПАРАМЕТРОВ все в порядке.
Код: Выделить всё
For I:=0 to C-1 do begin
T:= My_Thread.Create( True,....);
T.Start;
  Run_Test;// тут ограничение  количества одновременно работающих потоков
end;
Alex2013
долгожитель
 
Сообщения: 3124
Зарегистрирован: 03.04.2013 11:59:44

Пред.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 22

Рейтинг@Mail.ru