2009-12-20 2 views
4

У меня есть решение, где мне нужно быстро считывать объекты в память, однако бинарный поток может быть кэширован в памяти, чтобы сэкономить время на диске io.Параллельная двоичная десериализация?

Я искал разные решения, очевидно, XmlTextWriter и XmlTextReader не были настолько хороши, и ни одна из них не была встроенной двоичной сериализацией. Protobuf-net отлично, но все же немного медленнее. Вот некоторые статистические данные:

Размер файла XML: 217 кб

Размер

файла Binary: 87 кб

Сжатый Бинарные: 26 KB

Сжатый XML: 26 KB

Deserialize с XML (XmlTextReader): 8.4 сек.

Deserialize with Binary (Protobuf-net): 6.2 sek

Deserialize с Binary горе string.interning (Protobuf-нетто): 5,2 сек

Deserialize с Binary Из памяти: 5,9 Сек

Время для распаковки двоичного файла в память: 1.8 Сек

Serialize With Xml (XmlTextWriter): 11 сек

Сериализация с двоичным (Protobuf): 4 сек

Сериализация с двоичным префикс длины (Protobuf-нетто): 3,8 сек

Это заставило меня подумать, кажется (верьте мне, если я ошибаюсь), что основным виновником десериализации является фактическое преобразование байта, а не IO. Если это так, то это должен быть кандидат на использование новых параллельных расширений.

Поскольку я немного новичок, когда речь идет о двоичном IO я оценил бы некоторый входной сигнал, прежде чем я посвящаю время решения, хотя :)

Для простоты предположим, что мы хотим, чтобы десериализации список объектов без дополнительного поля. Моя первая идея состояла в том, чтобы просто сохранить каждый префикс длины. Прочитайте байт [] каждого в список байтов [] и используйте PLINQ для выполнения байта [] -> десериализации объекта.

Однако с этим методом мне все же нужно прочитать байта [] однократно, поэтому, возможно, можно было бы прочитать весь двоичный поток в памяти (насколько большие бинарные файлы возможны для этого btw?) И в начале двоичного кода вместо этого сохраните количество объектов и каждую их длину и смещение. Тогда я должен был бы просто создать ArraySegments или что-то еще и сделать chunking в paralllel тоже.

Так что вы, ребята, думаете, это возможно?

+0

Извините, некоторые вопросы Я действительно не получил определенного ответа, но в начале я просто не понял, чтобы установить его. Урок выучил и спасибо, указав это. Кажется, вы не можете ответить на старые вопросы, хотя я чего-то не хватает? – Homde

+0

В поддержку Алона, этот вопрос о сопоставлении строки java string, который вы опубликовали, имел некоторые замечательно хорошо продуманные ответы ... –

+0

Согласен, как мне задать правильный ответ? – Homde

ответ

0

я Deserialize при й списке объектов больше, то 1 MB XML я десериализация ля затем 2 секунды с этим кодом:

public static List<T> FromXML<T>(this string s) where T : class 
     { 
      var ls = new List<T>(); 
      var xml = new XmlSerializer(typeof(List<T>)); 
      var sr = new StringReader(s); 
      var xmltxt = new XmlTextReader(sr); 
      if (xml.CanDeserialize(xmltxt)) 
      { 
       ls = (List<T>)xml.Deserialize(xmltxt); 
      } 
      return ls; 
     } 

Попробуйте это, если это Бетер для случая XML?

+0

Сериализация xml работает так, но часть накладных расходов - это, вероятно, большое количество относительных небольших объектов, поэтому создание объектов становится проблемой. Тем не менее XML-сериализация почти никогда не быта, чем двоичная, и гораздо более многословная, что приводит к большему количеству времени из-за файла io – Homde

1

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

Предположим, что вы будете придерживаться простого двоичного формата: каждый объект имеет префикс своей длины. Зная, что вы можете «прокручивать» файл и знать смещение, куда помещать десериализующий поток.

десериализация Algoritm может выглядеть следующим образом: 1) анализируют файл (разделить его на несколько относительно крупных кусков, кусок границы должна coinside с объектом границей) 2) нерест необходимого количества десериализатора нитей и «наставлять» их соответствующие смещением и длина читать 3) объединить результаты всех потоков десериализации в один список

+0

Привет, я работаю над решением, подобным этому, но вместо того, чтобы читать с диска параллельно, я решил восстановить весь файл сначала буфер байта, а затем десериализовать/сериализовать его. Кажется намного быстрее, если вы читаете с диска параллельно, вы будете ограничены скоростью диска. Я напишу некоторую информацию о своем решении здесь, когда я закончу, спасибо – Homde

+0

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

0

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

Не предполагайте, где тратится время, получите себе профилировщик и узнайте.

2

Я делаю такие вещи довольно много, и ничто не сравнится с использованием BinaryReader для чтения вещей. Насколько я знаю, нет более быстрого способа, чем использование BinaryReader.ReadInt32 для чтения в 32-битном целочисленном.

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

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

+0

+1. Я делаю это слишком много, и BinaryReader - это путь. – zebrabox

Смежные вопросы