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

  • Что такое MemoryMappedFile?

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

Он имеет некоторые характеристики:

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

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

  • Как MemoryMappedFile используется в моем случае?

Я создаю файл с отображением памяти с (#processes * # threads in each process) байтами и использую его как массив байтов, где каждый индекс хранит флаг, указывающий, что i-й поток готов. В каждом потоке я использую цикл while, чтобы проверить, готовы ли все потоки среди всех процессов через файл отображения памяти, только после того, как все потоки будут готовы, поток начнет выполнять измерение. Если мы используем файл для синхронизации процессов, потребуется много операций ввода-вывода.

Ниже приведен код на Scala:

val communicationFile = new RandomAccessFile(fileForCommunicationName, "rw")
val communicationFileChannel = communicationFile.getChannel
val totalThreads = num_of_process * num_of_threads
val communicationFileBuffer = communicationFileChannel.map(FileChannel.MapMode.READ_WRITE, 0, totalThreads)
... do some other initializations
// Tell others that I am ready.
communicationFileBuffer.put((process_index * num_of_threads) + thread_index, 1)
// Wait for other processes
while (!0.until(totalThreads).forall((i) => communicationFileBuffer.get(i) == 1)) {

}
// Start to run my performance test.