Многопоточная десериализация с использованием BinaryFormatterC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Гость
 Многопоточная десериализация с использованием BinaryFormatter

Сообщение Гость »


Многопоточная десериализация с использованием BinaryFormatter или MessagePack не дает ожидаемого прироста производительности, и я пытаюсь понять, почему. Десериализация всех фрагментов одновременно происходит примерно в 5 раз медленнее, чем десериализация одного фрагмента для этой настройки.
Вот мой тестовый код с различными типами многопоточности. Используются Tasks, Threads и ParallelForEach, и самым быстрым на сегодняшний день является Threads.
Часки считываются перед выполнением десериализации, что означает, что никакая работа, связанная с вводом-выводом, не выполняется, и куски делятся на количество ядра у меня есть.

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

using System.Collections;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;

namespace SerializerDeserializeTests
{
public class Program
{
static void Main(string[] args)
{
int threads = 8;
int entries = 500000;
string directory = "data";
if(!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);

Hashtable hashtable = GenerateHashtable(entries);
List chunks = ChunkHashtable(hashtable, threads);
Export(chunks, directory);
}
else
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

List chunks = Directory.GetFiles(directory).Select(File.ReadAllBytes).ToList();

Console.WriteLine("Read: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

DeserializeParallelForEach(chunks).Clear();
DeserializeParallelForEachOneChunk(chunks).Clear();
DeserializeTasks(chunks).Clear();
DeserializeTasksOneChunk(chunks).Clear();
DeserializeThreads(chunks).Clear();
DeserializeThreadsOneChunk(chunks).Clear();
}
}

public static List DeserializeThreadsOneChunk(List chunks)
{
chunks = new List() { chunks[0] };
Console.WriteLine("----- DeserializeThreadsOneChunk -----");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

ConcurrentBag hashtables = new ConcurrentBag();
List threads = new List();
foreach (byte[] chunk in chunks)
{
Thread thread = new Thread(() =>
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using (MemoryStream memoryStream = new MemoryStream(chunk))
{
#pragma warning disable SYSLIB0011 // Type or member is obsolete
hashtables.Add((Hashtable)binaryFormatter.Deserialize(memoryStream));
#pragma warning restore SYSLIB0011 // Type or member is obsolete
}
});

threads.Add(thread);
thread.Start();
}

foreach (var thread in threads)
thread.Join();

Console.WriteLine("Deserialize: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return hashtables.ToList();
}
public static List DeserializeThreads(List chunks)
{
Console.WriteLine("----- DeserializeThreads -----");
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

ConcurrentBag hashtables = new ConcurrentBag();
List threads = new List();
foreach (byte[] chunk in chunks)
{
Thread thread = new Thread(() =>
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
using (MemoryStream memoryStream = new MemoryStream(chunk))
{
#pragma warning disable SYSLIB0011 // Type or member is obsolete
hashtables.Add((Hashtable)binaryFormatter.Deserialize(memoryStream));
#pragma warning restore SYSLIB0011 // Type or member is obsolete
}
});

threads.Add(thread);
thread.Start();
}

foreach (var thread in threads)
thread.Join();

Console.WriteLine("Deserialize: "  + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return hashtables.ToList();

общедоступный статический список< Hashtable> DeserializeTasksOneChunk(List chunks)
{
chunks = new List() { chunks[0] };
Console.WriteLine("-- --- DeserializeTasksOneChunk -----");
Секундомер stopwatch = new Stopwatch();
stopwatch.Start();

List задач = new List();
foreach (фрагмент byte[] в кусках)
{
Task Task = Task.Run(() =>
{
BinaryFormatterbinaryFormatter = new BinaryFormatter();
using (MemoryStream MemoryStream = new MemoryStream(chunk))
{
#pragma предупреждение отключить SYSLIB0011 // Тип или член устаревший
return (Hashtable)binaryFormatter.Deserialize(memoryStream);
#pragma alertrestore SYSLIB0011 // Тип или член устарел
 });

Tasks.Add(task);

Task.WaitAll(tasks.ToArray());

Console.WriteLine("Десериализовать: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return Tasks.Select(x => x.Result).ToList();
 public static List DeserializeTasks(List chunks)
{
Console.WriteLine("----- DeserializeTasks -----");
Секундомер секундомер = новый Stopwatch();
stopwatch.Start();

List задачи = новый List();
foreach (кусок byte[] в кусках)
{
Task Task = Task.Run(() =>
{
BinaryFormatterbinaryFormatter = new BinaryFormatter();
using (MemoryStream MemoryStream = new MemoryStream(chunk))
{
#pragma предупреждение отключить SYSLIB0011 // Тип или элемент устарел
return (Hashtable)binaryFormatter.Deserialize(memoryStream);< br />#pragma alertrestore SYSLIB0011 // Тип или элемент устарел
 });

Tasks.Add(task);

Task.WaitAll(tasks.ToArray());

Console.WriteLine("Десериализовать: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return Tasks.Select(x => x.Result).ToList();

public static List DeserializeParallelForEachOneChunk(List chunks)
{
chunks = new List() { chunks[0] };
Console.WriteLine("----- DeserializeParallelForEachOneChunk ---- -");
Секундомер stopwatch = new Stopwatch();
stopwatch.Start();

ConcurrentBag hashtables = new ConcurrentBag();
Parallel.ForEach(chunks, (chunk) =>
{
BinaryFormatterbinaryFormatter = new BinaryFormatter();
using (MemoryStream MemoryStream = new MemoryStream(chunk))
{
#pragma предупреждение отключить SYSLIB0011 // Тип или элемент устарел
hashtables.Add((Hashtable)binaryFormatter.Deserialize(memoryStream));
#pragma предупреждение восстановить SYSLIB0011 // Тип или элемент является устаревший
 });

Console.WriteLine("Десериализовать: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return hashtables.ToList();
 public static List DeserializeParallelForEach(List chunks)
{
Console.WriteLine( "----- DeserializeParallelForEach -----");
Секундомер stopwatch = new Stopwatch();
stopwatch.Start();

ConcurrentBag hashtables = новый ConcurrentBag();
Parallel.ForEach(chunks, (chunk) =>
{
BinaryFormatterbinaryFormatter = new BinaryFormatter();
using (MemoryStream MemoryStream = new MemoryStream(chunk))
{
#pragma предупреждение отключить SYSLIB0011 // Введите или элемент устарел
hashtables.Add((Hashtable)binaryFormatter.Deserialize(memoryStream));
#pragma alertrestore SYSLIB0011 // Тип или элемент устарел
 });

Console.WriteLine("Десериализовать: " + stopwatch.Elapsed.TotalSeconds);
stopwatch.Stop();

return hashtables.ToList();< br /> 
public static void Export(List chunks, stringdirectory)
{
Console.WriteLine("Экспорт фрагментов");
foreach (Чанк хеш-таблицы в кусках)
{
BinaryFormatterbinaryFormatter = new BinaryFormatter();
using (FileStream fileStream = new FileStream(directory + "\\chunk-" + Guid.NewGuid() + ".dat", FileMode.Create))
{
using(BinaryWriterbinaryWriter = new BinaryWriter(fileStream))
{
#pragma предупреждение отключить SYSLIB0011 // Тип или член устаревший
binaryFormatter.Serialize(binaryWriter.BaseStream, chunk);
#pragma alertrestore SYSLIB0011 // Тип или член устарел
    public static List ChunkHashtable(Hashtable Hashtable, int NumberOfChunks)
{
Console.WriteLine("Разбивка хэш-таблицы");
int chunkSize = hashtable.Count / NumberOfChunks;

int rester = hashtable.Count % NumberOfChunks;

var chunks = new List(numberOfChunks);

IDictionaryEnumerator enumerator = hashtable.GetEnumerator();
int elementsAdded = 0;

for (int i = 0; я Результат:
[code]Read: 0,0298205
----- DeserializeParallelForEach -----
Deserialize: 0,5175991
----- DeserializeParallelForEachOneChunk -----
Deserialize: 0,0809796
----- DeserializeTasks -----
Deserialize: 0,4418913
----- DeserializeTasksOneChunk -----
Deserialize: 0,193335
----- DeserializeThreads -----
Deserialize: 0,3709102
----- DeserializeThreadsOneChunk -----
Deserialize: 0,0767091
What I'm expecting is it should take the same amount of time to deserialize all chunks as one chunk.
Note: I know that BinaryFormatter shouldn't be used anymore but for my case it's fine.
Note2: MessagePack is even slower than BinaryFormatter and thus not included in my tests.


Источник: https://stackoverflow.com/questions/781 ... yformatter
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Сериализация BinaryFormatter в разное время для разных классов
    Гость » » в форуме C#
    0 Ответы
    22 Просмотры
    Последнее сообщение Гость
  • Замена BinaryFormatter в С#
    Anonymous » » в форуме C#
    0 Ответы
    31 Просмотры
    Последнее сообщение Anonymous
  • Исключение BinaryFormatter при попытке получить несуществующий ключ предпочтения в SettingsProperty в System.Configurati
    Anonymous » » в форуме C#
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous
  • BinaryFormatter десериализует вредоносный код?
    Anonymous » » в форуме C#
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Многопоточная сортировка слиянием с использованием платформы ForkJoin — отзывы о реализации
    Anonymous » » в форуме JAVA
    0 Ответы
    19 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»