Как обрабатывать миллиарды объектов без ошибки Outofmemory - PullRequest
0 голосов
/ 11 октября 2010

У меня есть приложение, которое может обрабатывать миллиарды объектов. Каждый объект имеет тип класса TRange.Эти диапазоны создаются в разных частях алгоритма, который зависит от определенных условий и других свойств объекта.В результате, если у вас есть 100 предметов, вы не можете напрямую создать сотый объект без создания всех предыдущих объектов.Если я создам все (миллиарды) объектов и добавлю в коллекцию, система выдаст ошибку Outofmemory.Теперь я хочу перебрать каждый объект в основном для двух целей:

  1. Чтобы применить операцию для каждого объекта TRange (например: Вывести определенные свойства)
  2. Чтобы получить кумулятивную суммуопределенное свойство. (Например: каждый диапазон имеет свойство веса, и я хочу получить общий вес, который является суммой всех весов диапазона).

Как эффективно создать итератор для этих объектов, не поднимаяOutofmemory?

Я обработал первый случай, передав указатель на функцию алгоритма.Например:

procedure createRanges(aProc: TRangeProc);//aProc is a pointer to function that takes a    //TRange
var range: TRange;
  rangerec: TRangeRec;
begin
  range:=TRange.Create;
  try 
    while canCreateRange do begin//certain conditions needed to create a range
      rangerec := ReturnRangeRec;
      range.Update(rangerec);//don't create new, use the same object.
      if Assigned(aProc) then aProc(range);
    end;
  finally
    range.Free;
  end;
end;

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

Спасибо всем заранееПрадип

Ответы [ 6 ]

8 голосов
/ 11 октября 2010

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

  1. I Создано расширенное хранилище, в котором можно хранить пользовательские записи либо в памяти, либо на жестком диске. В этом хранилище находится максимальное количество записей, которые могут одновременно храниться в памяти.
  2. Затем я извлек классы записей из пользовательского класса записей. Эти классы знают, как хранить и загружать себя с жесткого диска (я использую потоки).
  3. Каждый раз, когда вам нужна новая или уже существующая запись, вы запрашиваете такую ​​запись в расширенном хранилище. Если максимальное количество объектов превышено, хранилище передает часть некоторых наименее используемых записей обратно на жесткий диск.

Таким образом, записи прозрачны. Вы всегда получаете к ним доступ, как будто они находятся в памяти, но они могут быть загружены с жесткого диска в первую очередь. Это работает очень хорошо. Кстати, RAM работает очень похожим образом, поэтому на жестком диске хранится только определенное подмножество всех ваших данных. Тогда это ваш рабочий набор.

Я не публиковал какой-либо код, потому что он выходит за рамки самого вопроса и только запутает.

1 голос
/ 11 октября 2010

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

Обычно это делается так: вы пишете функцию перечислителя (как вы сделали), которая получает указатель на функцию обратного вызова (вы тоже это сделали) и нетипизированный указатель («Данные: указатель»).Вы определяете функцию обратного вызова, чтобы первый параметр был таким же нетипизированным указателем:

TRangeProc = procedure(Data: pointer; range: TRange);

procedure enumRanges(aProc: TRangeProc; Data: pointer);
begin
  {for each range}
    aProc(range, Data);
end;

Затем, если вы хотите, скажем, суммировать все диапазоны, вы делаете это следующим образом:

TSumRecord = record
  Sum: int64;
end;
PSumRecord = ^TSumRecord;

procedure SumProc(SumRecord: PSumRecord; range: TRange);
begin
  SumRecord.Sum := SumRecord.Sum + range.Value;
end;

function SumRanges(): int64;
var SumRec: TSumRecord;
begin
  SumRec.Sum := 0;
  enumRanges(TRangeProc(SumProc), @SumRec);
  Result := SumRec.Sum;
end;

В любом случае, если вам нужно создать миллиарды НИЧЕГО, вы, вероятно, делаете это неправильно (если вы не ученый, моделирующий что-то чрезвычайно масштабное и подробное).Тем более, если вам нужно создавать миллиарды вещей каждый раз, когда вам нужен один из них.Это никогда не хорошо.Попробуйте придумать альтернативные решения.

1 голос
/ 11 октября 2010

Посмотрите на TgsStream64. Этот класс может обрабатывать огромные объемы данных посредством сопоставления файлов.

http://code.google.com/p/gedemin/source/browse/trunk/Gedemin/Common/gsMMFStream.pas

0 голосов
/ 11 октября 2010

Возможна обработка миллиардов объектов, но вам следует избегать этого как можно больше. Делайте это, только если вам абсолютно необходимо ...
Однажды я создал систему, которая должна была обрабатывать огромное количество данных. Для этого я сделал свои объекты «потоковыми», чтобы их можно было читать / записывать на диск. Большой класс вокруг него использовался, чтобы решить, когда объект будет сохранен на диск и, таким образом, удален из памяти. По сути, когда я вызываю объект, этот класс проверяет, загружен он или нет. Если нет, он заново создаст объект с диска, поместит его поверх стека и затем переместит / запишет нижний объект из этого стека на диск. В результате мой стек имел фиксированный (максимальный) размер. И это позволило мне использовать неограниченное количество объектов, причем с неплохой производительностью.
К сожалению, у меня больше нет этого кода. Я написал это для предыдущего работодателя около 7 лет назад. Я знаю, что вам нужно было бы написать немного кода для поддержки потоковой передачи плюс еще кучу для контроллера стека, который поддерживает все эти объекты. Но технически это позволит вам создавать неограниченное количество объектов, поскольку вы торгуете оперативной памятью дисковым пространством.

0 голосов
/ 11 октября 2010

Эта часть:

В результате, если у вас есть 100 предметов, вы не можете напрямую создать сотый объект без создания всех предыдущих объекты.

звучит немного похоже на вычисление Фибоначчи. Может быть, вы можете повторно использовать некоторые объекты TRange вместо создания избыточных копий? Здесь - это статья на C ++, описывающая этот подход - он работает, сохраняя уже вычисленные промежуточные результаты в хэш-карте.

0 голосов
/ 11 октября 2010

У «Бегуна» есть хороший ответ, как с этим справиться!

Но я хотел бы знать, не могли бы вы сделать быстрое решение: создать меньшие объекты TRange Может быть, у вас есть большой предок? Можете ли вы взглянуть на размер экземпляра объекта TRange? Может, тебе лучше использовать упакованные записи?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...