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

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

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

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

Сообщение Alex2013 » 20.02.2025 15:12:57

xchgeaxeax писал(а):А причем тут виртуализация, когда речь про скорости дисков. А на виртуалке там будет так и так прокладка в виде этой самой виртуалки.

В том то и фокус "аппаратной виртуализации" что она может рулить железом напрямую (То есть "Гостевая ОС" по идее может получить аппаратный доступ к физическому разделу диска или целому физическому диску ( причем иногда даже в том случае если основная "хост-ОС" совершенно "не подозревает о его существании") возни там правда может быть довольно много но иногда это оправдано)
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение xchgeaxeax » 20.02.2025 15:34:20

Ну вот это надо диск подключать напрямую, а не использовать файл. Это как раз и замедляет. Какой смысл в таком тестировании.
xchgeaxeax
постоялец
 
Сообщения: 173
Зарегистрирован: 11.05.2023 03:51:40

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

Сообщение sts » 21.02.2025 13:47:25

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

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

Сообщение Alex2013 » 22.02.2025 12:47:53

Брр ... JPEGImage.LoadFromStream(ST); (JPEGImage:TFPMemoryImage) достал ! Нормально читать поток (MemoryStream) с произвольной позиции не хочет совершенно (упроно читает только первую картинку в потоке) причем закидон где-то в TFPReaderJPEG .(Пробовал сделать "заплатку" но тут этот фокус не прошел)

Так что пока плюнул и написал простой конвертер Jpg2Bmp...
(он работает но с потерей универсальности TFPMemoryImage)
Код: Выделить всё
Function Jpg2Bmp( jpg:TStream ):TBitmap;
var b:TBitmap;
   j:TJPEGImage;
begin
result := nil;
try
   j :=TJPEGImage.Create;
   try
     j.LoadFromStream(jpg);
      b := TBitmap.Create;
     try
       b.Assign(j);
    except
     FreeAndNil(B);
     end;
   finally
     j.Free;
   end;
   Result:=B;
except
   Result := Nil;
end;
end;

Зы
Вообщем пока я все еще пытаюсь протащить контейнер из "общего " MemoryStream, но уже начинаю сомневаться "так ли это полезно как красиво" . :roll:

Добавлено спустя 18 минут 45 секунд:
sts писал(а):раньше, как тока появились многоядерные процы, максимально эффективное к-во потоков было = к-во ядер минус одно для операционной системы, последние лет 10, минус два ядра, один для IO, другой для менеджера потоков.

Раньше я тоже думал примерно так-же и постоянно пытался подстроится под количество "физических" потоков и ядер .
Но потом выяснилось что использование заметно большего количества "виртуальных потоков" ускоряет работу "распараллеленных" алгоритмов более чем успешно . (Что очень наглядно видно и на примере моей "тестовой платформы" )
Последний раз редактировалось Alex2013 22.02.2025 15:51:59, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение xchgeaxeax » 22.02.2025 14:03:03

Может проще сделать дополнительный стрим TPartialStream = class(TStream) constructor Create(Source: TStream; Offset: Int64; Size: Int64); соответственно она нужна просто для того, чтобы скормить ей TMemoryStream, из которого она будет отдавать только указанный в конструкторе кусочек от Offset до Offset + Size

Не копировать в себя, а сохранять исходный TMemoryStream и при загрузке через LoadFromStream считывать из него заданный диапазон
xchgeaxeax
постоялец
 
Сообщения: 173
Зарегистрирован: 11.05.2023 03:51:40

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

Сообщение Alex2013 » 22.02.2025 15:48:30

xchgeaxeax писал(а):Может проще сделать дополнительный стрим TPartialStream = class(TStream) constructor Create(Source: TStream; Offset: Int64; Size: Int64); соответственно она нужна просто для того, чтобы скормить ей TMemoryStream, из которого она будет отдавать только указанный в конструкторе кусочек от Offset до Offset + Size

Не копировать в себя, а сохранять исходный TMemoryStream и при загрузке через LoadFromStream считывать из него заданный диапазон

Это разумеется тоже вариант (причем он точно лучше чем просто копировать текущую картинку в дополнительный поток или неким "хитрым образом" подменять адрес блока данных (первый вариант работает хотя и подтормаживает , а на второй видимо моей "хитрости" не хватило )) ... но это все равно "костыль" ! :( Однако попробовать можно. Спасибо !

Добавлено спустя 2 часа 42 минуты 56 секунд:
Заплатка работает !
Код: Выделить всё
Type
     TTmpStream = class(TMemoryStream)
          F_Offset: Int64;
           constructor Create;
           function Read(var Buffer; Count: Longint): Longint; Override;
     end;
   constructor  TTmpStream .Create;
     begin
       F_Offset:= 0;
     inherited Create;

     end;
   function  TTmpStream.Read(var Buffer; Count: Longint): Longint;

   begin
   If  Position< F_Offset then
      Position:= Position+F_Offset;
       inherited;
    end;
...
TTmpStream(MS).F_Offset:=PPos^.P;
B:=LoadAndScaleImage('',W,H,Ms,Pos^.P);
TTmpStream(MS).F_Offset:=0;
..

Правда это сугубо локальное "местечковое" решение которое работает только потому что в цикле ничего другого кроме "последовательного" LoadAndScaleImage нет
.
Последний раз редактировалось Alex2013 09.03.2025 07:03:51, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение Alex2013 » 27.02.2025 04:04:57

Еще немного оптимизировал код (отказался о своего "самодельного" масштабирования в пользу того что доступно в TFPMemoryImage неуверен что это масштабирование быстрее но оно заметно уменьшает объем данных которые прокачиваются при "конверсии" в TBitmap )
В общем однопоточную загрузку IrfanView вполне догнал и возможно даже немного перегнал.
Тест загрузки списка 3 (30 "стандартных" файлов)
Время 0,12 c
Время 2,68 c
Тест загрузки списка 3 (78 "тяжелых" файлов)
Время 0,34 c
Время 10,76 c
Тест загрузки списка 3 ( "Стресс тест" 639 "тяжелых" файлов )
Время 39,03 c
Время 114,86 c
Тест загрузки списка 2 ( "Стресс тест" 639 "тяжелых" файлов )
Многопоточный ( версия 2 ("Старая" но с новым масштабированием ) 40 потоков )
Время 103,53 c 639

(Нужно дописать Многопоточную загрузку для "3-й версии" по идее будет еще быстрее )
Зы
Кстати я еще и качество миниатюр поднял
Код: Выделить всё
//вместо
// JPEGImage.LoadFromStream(ST);
//написал
       R:= TFPReaderJPEG.Create;
        TFPReaderJPEG(R).Smoothing:=true;
        TFPReaderJPEG(R).Scale:=jsQuarter;
        TFPReaderJPEG(R).ImageRead(ST,JPEGImage);
       R.Free;
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение Alex2013 » 07.03.2025 20:06:51

Новая фишка
"Трехфазная " загрузка

Тест загрузки списка 3 (78 "тяжелых" файлов)
Время 0,04 c (Разметка)
Время 0,25 c ( загрузка без промежуточного потока) )
Время 11,77 c ( обработка )

Тест загрузки списка 3
Время 0,04 c
Время 0,18 c ( загрузка с промежуточным потоком)
Время 11,03 c ( обработка )

Тест загрузки списка 3 (немного странный результат ) 82 файла
Время 0,04 c
Время 0,19 c
Время 11,75 c
Тест загрузки списка 3
Время 0,05 c
Время 0,26 c
Время 11,31 c

Тест загрузки списка 2
Многопоточный (45 потоков)
Время 15,05 c 82

Суть "нулевой фазы" в разметке потока для последующей загрузки ( нужно для многопоточного чтения из файлов )
(обработка/загрузка пока однопоточные но уже немного обгоняет старую многопоточную )
Последний раз редактировалось Alex2013 09.03.2025 06:55:59, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение xchgeaxeax » 08.03.2025 00:16:42

А в чем смысл "разметки". Можно пример?
xchgeaxeax
постоялец
 
Сообщения: 173
Зарегистрирован: 11.05.2023 03:51:40

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

Сообщение Alex2013 » 08.03.2025 15:37:57

xchgeaxeax писал(а):А в чем смысл "разметки". Можно пример?


"Звучит гордо, но жужжит тихо " :wink: Да вся "фаза 0" это просто предварительный расчет общего размера для мемористрима и запись списка позиций для каждой картинки( При многопоточном варианте поток будет заполняется не по порядку а рандомным образом, а значит просто добавить запись в поток не получится )
Код: Выделить всё
///Фаза 0
//"Форматирование потока"
SumSZ:=0;
For I:=0 to CC-1 do
begin
L.Add(Nil);
//....
CacheFilename := Memo1.Lines[I];
if  FileExists(CacheFilename) then begin
SZ:= getFileSize (CacheFilename);

If SZ<>-1 then
begin
   Tpos:=SumSZ;
   SumSZ:=SumSZ+SZ;
   
    New(PPos); PPos^.P:=TPos;PPos^.S:=SZ; L[I]:=PPos;
  end
end
end;
MS1.SetSize(SumSZ); // (!)

Зы
Нужно подумать как это действие для сетевой версии провернуть ... с получением размера не загруженного файла там точно напряженка будет.
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение xchgeaxeax » 08.03.2025 17:01:11

А чем вам не нравится вариант с отдельным стримом для каждого файла? Просто соберите указатели на объекты в массив или лист и все.
xchgeaxeax
постоялец
 
Сообщения: 173
Зарегистрирован: 11.05.2023 03:51:40

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

Сообщение Alex2013 » 09.03.2025 02:46:22

xchgeaxeax писал(а):А чем вам не нравится вариант с отдельным стримом для каждого файла? Просто соберите указатели на объекты в массив или лист и все.

Идея в том что "единая лента" глобального мемористрима будет еще немного меньше взаимодействовать с элементами программы и операционной системы внутри многопоточной части процедуры загрузки что еще немного уменьшит возможность асинхронных коллизии .
(И дело не в том что я против "отдельного стрима для каждого файла" если можно выделить память для каждого файла ДО его загрузки то это тоже неплохой вариант (хотя и чуть более сложный в плане контроля выделения и очистки памяти ) )
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение xchgeaxeax » 09.03.2025 12:13:59

Alex2013 писал(а):(И дело не в том что я против "отдельного стрима для каждого файла" если можно выделить память для каждого файла ДО его загрузки то это тоже неплохой вариант (хотя и чуть более сложный в плане контроля выделения и очистки памяти ) )

Для предопределения размеров файла вы по прежнему генерируете медленные операции с диском. А вот дополнительные взаимодействия по выделению рам идут гораздо быстрее таковых. В принципе должно работать быстрее, если вы просто будете грузить отдельно каждый файл в каждом потоке просто создавая новый мемористрим и сохраняя его в массив / лист. Так будет меньше дисковых операций чтения, а вот операции с памятью и поиску блоков в куче должны быть достаточно быстрыми. К тому же ОС обычно переадресует работу с памятью для загрузки блока данных от медленного устройства в контроллер DMA, что освобождает процессор для выполнения работы в это время. Может для ускорения стоит рассмотреть конвейер: поток для загрузки (достаточно одного т.к. мы уже выяснили, что эти операции быстрее чем само перекодирование), несколько потоков перекодирования, которые выбирают свой мемори стрим из потока загрузки сразу по готовности. В такой схеме должно происходить следующее. Процессор занят перекодированием загруженной картинки во время пока DMA контроллер передает данные в очередной блок памяти при загрузке. Ну а по готовности нового блока, скорее всего, поток перекодирования все еще будет занят и новый поток перекодирования заберет следующий блок в работу итд.
xchgeaxeax
постоялец
 
Сообщения: 173
Зарегистрирован: 11.05.2023 03:51:40

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

Сообщение Alex2013 » 11.03.2025 15:28:32

xchgeaxeax писал(а):Для предопределения размеров файла вы по прежнему генерируете медленные операции с диском. А вот дополнительные взаимодействия по выделению рам идут гораздо быстрее таковых.

Я тоже нивно думал что выделение памяти много времени не занимает и вначале код "фазы ноль"
был такой
Код: Выделить всё
///Фаза 0
//"Форматирование потока"

For I:=0 to CC-1 do
begin
//....
SZ:= getFileSize (CacheFilename);

If SZ<>-1 then
begin
..
   MS1.Size:=MS1.Size+SZ; // (!)
..
end
end
end;

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

Проблема коллизий всеравно сохраняется (раз выделение памяти как выясняется занимает заметное время то есть вероятность совпадения нескольких выделений, перекрытия областей памяти и прочих неприятностей . )
К тому же ОС обычно переадресует работу с памятью для загрузки блока данных от медленного устройства в контроллер DMA,

Загрузка болка данных с "блочного устройства" в память ВСЕГДА происходит через "контроллер DMA" но что с эти блоком ( при многократной буферизации и кэшировании ) происходит дальше дело довольно темное .
К тому же тут вопрос в значительной степени не про чтение файла а про реализацию мемористрима. (как известно он хорошо и надежно работает при последовательном чтении загруженных в него данных но совсем остальным как говорится "возможны варианты" );
Alex2013
долгожитель
 
Сообщения: 3117
Зарегистрирован: 03.04.2013 11:59:44

Пред.

Вернуться в Lazarus

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

Сейчас этот форум просматривают: jsa и гости: 22

Рейтинг@Mail.ru