Поиск на сайте
Главная Журнал Форум Wiki DRKB Страны мира

Введение в Memory-Mapped Files

Автор: Vipul Patel

Введение

В .NET Framework есть API-интерфейсы для редактирования файла, однако API, поставляемые в версиях до .NET Framework 4.0 не предназначены для работы с очень большими файлами. В потоковом классе MemoryStream (в отличие от FileStream) нет буферизации инкапсулированных данных и они напрямую помещаются в память. При отсутствии резервной копии данных, MemoryStream может оказаться полезным в качестве временного буфера. Memory-Mapped Files описываются в MSDN как способ, позволяющий приложениям работать с файлами так же как они работают с динамической памятью. Полная статья по Управлению отображаемыми в память файлами находится на сайте MSDN.

Типы отображаемых в памяти файлов

В библиотеке .NET framework 4.0 классы для работы с memory-mapped files находятся в пространстве имён System.IO.MemoryMappedFiles. Есть два основных типа отображаемых в память файлов:

- Persisted Files (Сохраняемые файлы) - Эти файлы имеют связанный с ними физический файл на диске. Эти типы файлов используются при работе с очень большими объёмами. При этом в память загружается только часть такого файла.

- Non-persisted files (Не сохраняемые файлы) - Эти файлы не имеют связанного с ними физического файла на диске, и при завершении процесса их содержимое теряется. Обычно такие файлы используются для взаимодействия между процессами и называются IPC.

Преимущества отображаемых в памяти файлов

Одним из основных преимуществ использования memory-mapped files, это увеличение производительности при операциях чтения/записи в загруженный в память файл. Доступ к памяти происходит быстрее, чем дисковые операции ввода/вывода, следовательно, повышение производительности достигается и при работе с очень большими файлами.

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

Недостатки Memory-Mapped Files

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

Работа с отображаемыми в память файлами

Работа с отображаемыми в память файлами происходит путём создания представления части или полного содержимого файла.

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

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

Для IPC, Ваш отображаемый в память файл потребует отображение MemoryMappedViewAccessor имеющее доступ к оперативной памяти, и может быть создано вызовом метода CreateViewAccessor в экземпляре MemoryMappedFile.

Пример приложения с использованием Сохраняемого Memory Mapped File

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

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO;
  using System.IO.MemoryMappedFiles;
  
  namespace PersistentMemoryMappedFile
  {
      class Program
      {
          static string LargeString = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000.";
          static void Main(string[] args)
          {
              CreateLargeFile();
              CreateMemoryMappedFile("largetextfile.txt");
  
          }
  
          private static void CreateMemoryMappedFile(string fileName)
          {
              FileInfo fInfo = new FileInfo(fileName);
              long length = fInfo.Length;
              MemoryMappedFile mySequentialMMF = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, "MySequentialMap");
              for (long i = 0; i < length; i = i + 100000)
              {
                  MemoryMappedViewStream myMMFViewStream = mySequentialMMF.CreateViewStream(0, 100000, MemoryMappedFileAccess.ReadWrite);
                  myMMFViewStream.WriteByte((byte)'A');
                  Console.WriteLine("We changed a bit");
              }
          }
  
          private static void CreateLargeFile()
          {
              using (StreamWriter sw = new StreamWriter("largetextfile.txt", false))
              {
                  for (int i = 0; i < 500000; i++)
                      sw.WriteLine(LargeString);
              }
              File.Copy("largetextfile.txt", "largetextfileoriginal.txt");
  
          }
      }
  }

Листинг 1

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

Пример MemoryMappedFile для межпроцессного взаимодействия

Давайте посмотрим пример использования отображаемой памяти файлов для связи между процессами. В примере приведены два приложения: одно записывает, а другое считывает. Листинг записывающего приложения:

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO.MemoryMappedFiles;
  using System.IO;
  using System.Threading;
  namespace NonPersistedMemoryMappedFileA
  {
      class Program
      {
          static void Main(string[] args)
          {
              MemoryMappedFile myNonPersisterMemoryMappedFile = MemoryMappedFile.CreateNew("myNonPersisterMemoryMappedFile", 100);
              bool IsmutexCreated;
              Mutex mymutex = new Mutex(true, "NonPersisterMemoryMappedFilemutex", out IsmutexCreated);
              Console.WriteLine("Start NonPersisterMemoryMappedFileB now");
              Console.ReadLine();
  
              StreamWriter sw = new StreamWriter(myNonPersisterMemoryMappedFile.CreateViewStream());
              sw.WriteLine("Process A says Hi");
              sw.Close();
              mymutex.ReleaseMutex();
  
          }
      }
  }

Листинг 2 - NonPersistedMemoryMappedFileB.cs


Компилируется вышеприведённый код в NonPersistedMemoryMappedFileA.exe с помощью следующей команды:

  C:\windows\microsoft.net\frame work\v4.0.30319\csc.exe NonPersistedMemoryMappedFileA.cs

Теперь листинг читающего приложения:

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.IO.MemoryMappedFiles;
  using System.IO;
  using System.Threading;
  
  namespace NonPersistedMemoryMappedFileB
  {
      class Program
      {
          static void Main(string[] args)
          {
              MemoryMappedFile myNonPersisterMemoryMappedFile = MemoryMappedFile.OpenExisting("myNonPersisterMemoryMappedFile");
              Mutex mymutex = Mutex.OpenExisting("NonPersisterMemoryMappedFilemutex");
              mymutex.WaitOne();
  
              StreamReader sr = new StreamReader(myNonPersisterMemoryMappedFile.CreateViewStream());
              Console.WriteLine(sr.ReadLine());
              sr.Close();
              mymutex.ReleaseMutex();
  
              StreamWriter sw = new StreamWriter(myNonPersisterMemoryMappedFile.CreateViewStream());
              sw.WriteLine("Process B says Hi");
              sw.Close();
  
          }
      }
  }

Листинг 3 - NonPersistedMemoryMappedFileB.cs


Этот код компилируется в NonPersistedMemoryMappedFileB.exe с помощью следующей команды:

  C:\windows\microsoft.net\framework\v4.0.30319\csc.exe NonPersistedMemoryMappedFileB.cs

После компиляции откройте командную строку и выполните NonPersistedMemoryMappedFileA.exe. После появления просьбы запустите NonPersistedMemoryMappedFileB.exe и нажмите Enter в окне NonPersistedMemoryMappedFileA.exe. После этого будет видно как приложение NonPersistedMemoryMappedFileB.exe выводит сообщения посылаемы ему из NonPersistedMemoryMappedFileA.exe.

Статьи по Теме

• Введение в Code Access Security в .NET Framework
•.NET Framework: Monitor a Directory for a New File and Use FTP Upload to Copy It
• Изменения в классах System.IO в .NET Framework 4.0

Скачать

MemoryMappedFilesDemo.zip (78кб)




Основные разделы сайта


 

Реклама Читайте статью "Что такое домен и хостинг?" на сайте http://www.0564.ua/list/59239.