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

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

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

Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Возился с улучшением сетевой загрузки и пришел к "парадоксальному" выводу что "нафига козе баян" ...
Сильно упрощенная версия (Слегка быстрее и намного надежнее)...
Основная идея та же самая : "толстые" нити но в малом количестве.

Код: Выделить всё

TLoadableFileThread = class(TThread)
private
AName,  MSG: String;
fFileNames: TStringList;
AData : TMemoryStream;
FWork: Boolean;
 procedure GetNext;
protected
  procedure Execute; override;
public
 Procedure  SLog;
 Procedure  SyncLog(M:String);
 Procedure  SyncLoad;
 Procedure  Load;
 constructor Create(FileNames: TStringList);
 destructor Destroy; override;
end;

Procedure  TLoadableFileThread.SLog;
begin
LSIForm.Memo3.Lines.Add(MSG);
end;
Procedure   TLoadableFileThread.SyncLoad;
begin
Application.ProcessMessages;
 OneDraw(AName,AData);
end;
Procedure   TLoadableFileThread.Load;
var
  F:Integer;
  HTTPClient :TFPHttpClient;
begin
if (Pos('http://', LowerCase(AName)) > 0) or
   (Pos('https://', LowerCase(AName)) > 0)
then begin
  F :=  2; //2 попытки прочитать, если нужно.
  while F > 0 do begin
  HTTPClient := TFPHttpClient.Create(nil);
  AData := TMemoryStream.Create;
  try
    HTTPClient.Get(AName, AData);
    AData.Position := 0; //!! Сброс позиции в потоке  !!!
                        // (Без него ничего не работает )
    F:=-1;
  except
  Sleep(20);
   F:=F-1;
  end ;
  HTTPClient.Free;
 end;
if F = 0 then FreeAndNil(AData);
Synchronize(SyncLoad);
AData.Free;
end
else
  begin
AData:=nil;
 if  FileExists(Aname) then
  begin
    AData:=TMemoryStream.Create;
     try
       AData.LoadFromFile(AName);
       AData.Position := 0;
      except
       FreeAndNil( AData)
     end;
  end;
 Synchronize(SyncLoad);
 AData.Free;
 end
end;

Procedure  TLoadableFileThread.SyncLog(M:String);
begin
MSG:=M;
Synchronize(Slog);
end;

constructor TLoadableFileThread.Create(FileNames: TStringList);
begin
inherited Create(True);
FreeOnTerminate := False;
AName := '';
fFileNames:=FileNames;
ind:=0;
FWork := False;
end;

destructor TLoadableFileThread.Destroy;
begin
FreeOnTerminate:=True;
if not Terminated then Terminate;
inherited Destroy;
tLoadders.Delete(tLoadders.IndexOf(Self));
 //Для лучшего контроля завершения работы потока  
end;

procedure TLoadableFileThread.GetNext;
begin
FWork := False;

If  (fFileNames<>Nil) and
    (fFileNames.Count >0 )
then begin

EnterCriticalSection(x);
  AName:= fFileNames[0];
  fFileNames.Delete(0);
  FWork := fFileNames.Count>=0;

 LeaveCriticalSection(x);
end else
 begin
 SyncLog(' Поток ' + IntToStr(ThreadID) + ' завершает работу');
 FreeOnTerminate := True;
 Terminate;

end;

end;
procedure TLoadableFileThread.Execute;
var
i: LongInt;
S:String;
FromInternet:Boolean;
begin
SyncLog('Запуск ...');
while not Terminated do begin
 GetNext;
  if FWork then Load else sleep(iThreadWaitTimeout);
end;
end;
Почему надежнее ? Потому что обработка происходит сразу (точнее по мере поступления данных) что заметно экономит память .
А быстрее за счет уменьшения синхронизированного участка кода (по сути синхронизируется только непосредственно "внешняя обработка" в процедуре OneDraw ).

Еще добавил список потоков tLoadders удобная штука для контроля процесса загрузки (можно сделать прогресс бар ),аварийного завершения работы загрузчика, контроля завершения загрузки (так как элементы списка удаляются непосредственно в деструкторе никаких накладок быть не может ) и возможно своевременного уничтожения повисших нитей-потоков . (но там нужно хорошенько подумать как это можно сделать максимально надежно без ложного срабатывания если поток просто замедлился но не повис )
Seenkao
энтузиаст
Сообщения: 569
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

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

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

К чему я это всё? Возможно где-то в коде у тебя нагрузка проявляется, которую ты не хочешь видеть или просто не видишь. Попробуй профилировщик, может он поможет выявить лишнюю нагрузку. И потоки могут оказаться не при чём. )))
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Seenkao писал(а):К чему я это всё? Возможно где-то в коде у тебя нагрузка проявляется, которую ты не хочешь видеть или просто не видишь. Попробуй профилировщик, может он поможет выявить лишнюю нагрузку. И потоки могут оказаться не при чём. )))
К дождю! :wink: В принципе верно я уже неплохо оптимизировал однопоточный код так что он идет "ноздря к ноздре" к монгопоточному . :idea:
Сквозняк
энтузиаст
Сообщения: 1159
Зарегистрирован: 29.06.2006 22:08:32

Сообщение Сквозняк »

Alex2013 писал(а):однопоточный код так что он идет "ноздря к ноздре" к монгопоточному
А у процессора сколько потоков?
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Сквозняк писал(а):А у процессора сколько потоков?
На одной железке 4 -е на другой 8-мь . (Но как я писал ускорение заметно лучше ощущается, при использовании на порядок большего количества "программных" потоков причем все работает без потери стабильности) Да, можно вместо "большего количества "программных" потоков " немного поднять приоритет исполнения потока, но это уже может заметно подтормаживать "внешнюю ОС". ( Хотя нужно проверить как это сказывается на новых версиях кода)

ЗЫ
Ускорение от использования "многопоточного режима" разумеется все рано есть но после оптимизации однопоточной загрузки оно уже скажем так "не сильно впечатляет".
Seenkao
энтузиаст
Сообщения: 569
Зарегистрирован: 01.04.2020 02:37:12
Контактная информация:

Сообщение Seenkao »

Alex2013 писал(а):после оптимизации однопоточной загрузки оно уже скажем так "не сильно впечатляет".
тут уже многопоточную работу надо оптимизировать. Производить загрузку данных -> отправлять данные на обработку + производить загрузку данных -> отправлять данные на обработку + производить загрузку данных -> ...

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