Как параллельно обрабатывать данные в файле с отображением памяти

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

  1. Является ли MemoryMappedFileViewAccessor потокобезопасным и Parallel.For-безопасным? На самом деле я сделал демонстрационную программу, чтобы проверить вопрос, и, похоже, она работает. Но не могу найти никаких упоминаний об этом. Если ответ да, я закончил. В противном случае,
  2. Есть ли способ напрямую получить доступ к памяти, отображаемой с помощью массива? Я знаю, что MemoryMappedFileViewAccessor имеет метод ReadArray, но использование этого метода является дублированием памяти.

person Tae-Sung Shin    schedule 03.05.2013    source источник
comment
ваша параллельная обработка включает изменение файла или только чтение из него?   -  person Charles Lambert    schedule 04.05.2013
comment
@CharlesLambert Нет, обработка данных включает операции accessor.Write или accessor.Read, которые в основном обращаются к отображаемой памяти. Файл с отображением памяти фактически заботится об операции с файлом.   -  person Tae-Sung Shin    schedule 04.05.2013


Ответы (3)


Вы можете обосновать это. Файл с отображением памяти — это просто кусок памяти в вашей программе, байты которого доступны более чем одному процессу. Они довольно неудобны в управляемом коде, поскольку этот фрагмент существует по определенному адресу. Что требует доступа к данным с помощью указателя, они табуированы в управляемом коде. MemoryMappedFileViewAccessor упаковывает этот указатель, он копирует данные из управляемой памяти в общую память. Обратите внимание, что это отменяет основную причину использования MMF и то, почему их поддержка так долго не появлялась в .NET. Убедитесь, что вместо этого вы не хотите использовать именованные каналы.

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

Также обратите внимание, что вам необходимо реализовать эту блокировку между процессами, которые читают и пишут MMF. Что, как правило, болезненно, вы должны использовать именованный мьютекс, который создает «главный» процесс, и открывается «подчиненный» процесс. Вы не можете экономить на этом требовании блокировки. Примечательно, что вы никогда не упоминали об этом в своем вопросе, так что красный флаг.

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

person Hans Passant    schedule 03.05.2013

Внутри MemoryMappedViewAccessor является производным от UnmanagedMemoryAccessor, который кажется неизменяемым, хотя и не имеет полей только для чтения — по крайней мере, он не изменяет существующие поля во время операций чтения/записи, что делает его потокобезопасным. В свою очередь, он считывает данные файла с отображением памяти из SafeBuffer, который содержит следующий текст в заголовок комментариев:

/* Keep the penalties for using this class small, both in terms of space 
// and time.  Having multiple threads reading from a memory mapped file
// will already require 2 additional interlocked operations.  If we add in 
// a "current position" concept, that requires additional space in memory and 
// synchronization.  Since the position in memory is often (but not always)
// something that can be stored on the stack, we can save some memory by 
// excluding it from this object.  However, avoiding the need for
// synchronization is a more significant win.  This design allows multiple
// threads to read and write memory simultaneously without locks (as long as
// you don't write to a region of memory that overlaps with what another 
// thread is accessing).

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

person Alexander    schedule 03.05.2013

1) MSDN заявляет как для MemoryMappedFile, так и для MemoryMappedViewAccessor следующее:

Любые общедоступные статические (общие в Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют потокобезопасность.

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

person Charles Lambert    schedule 03.05.2013
comment
Файлы, отображаемые в память @Thomas, конечно, по-прежнему потребляют адресное пространство. На самом деле безымянный файл с отображением памяти не сильно отличается от низкоуровневого распределения памяти ОС с той же степенью детализации. - person Neil; 16.05.2013