Перейти к содержанию
    

Ускорить запись в файл в Windows

Есть задача: принимать данные от аппаратуры программой1 и через файл передавать их в программу2. Действие происходит в Windows XP.

При этом не устраивает скорость записи данных в файл. Передача осуществляется средствами WinAPI.

Есть ли более быстрые способы передачи данных?

Желательно минимальное изменение изменение кодов программ по причине того, что программу 1 и 2 делают разные люди.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть задача: принимать данные от аппаратуры программой1 и через файл передавать их в программу2. Действие происходит в Windows XP.

При этом не устраивает скорость записи данных в файл. Передача осуществляется средствами WinAPI.

Есть ли более быстрые способы передачи данных?

Желательно минимальное изменение изменение кодов программ по причине того, что программу 1 и 2 делают разные люди.

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

 

А если нужен обмен между двумя программами на одном и том же компьютере, то надо открывать "виртуальные" файлы - файлы, отображаемые на память (при помощи функции API CreateFileMapping()). О том, как это делается, читайте тут - http://frolov-lib.ru/books/bsp/v27/ch1_1.htm

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за ответ!

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выбирайте что больше нравится из Interprocess Communications

 

если переходить от записи/чтения файлов, то минимум изменений, вероятно, потребуется для механизма Pipes

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если нужен обмен между двумя программами на одном и том же компьютере, то надо открывать "виртуальные" файлы - файлы, отображаемые на память (при помощи функции API CreateFileMapping()). О том, как это делается, читайте тут - http://frolov-lib.ru/books/bsp/v27/ch1_1.htm

 

Попробовал сделать при помощи файлов, отображаемых на память.Вопрос: какого размера файл лучше всего загружать? Долго тестировал этот параметр. Смотрел время,затрачиваемое на запись в файл (при помощи QueryPerformanceCounter). У меня получилась линейная зависимость (чем меньше файл, тем быстрее он записывается).Это правильный вывод?Просто я слышал рекомендации на тему того, что файл должен быть выровнен по границе страницы памяти...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос: какого размера файл лучше всего загружать? Долго тестировал этот параметр. Смотрел время, затрачиваемое на запись в файл (при помощи QueryPerformanceCounter). У меня получилась линейная зависимость (чем меньше файл, тем быстрее он записывается). Это правильный вывод? Просто я слышал рекомендации на тему того, что файл должен быть выровнен по границе страницы памяти...

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно попробовать сделать виртуальный диск и именно там расположить файл. Это позволит не переделывать программы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как выше советовали, можно использовать именованные каналы (named pipes), тогда программы смогут общатся даже в пределах сети. А писать и читать можно стандартными Read/WriteFile.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не буду слишком категоричной, но в отношении механизма pipes у меня имеются опасения. Pipe - канал между приложениями, а потому быстро записывать в его можно будет только тогда, когда приложение-приемник более прожорливое, чем тот поток данных, который отправляется ему в рот. Если оно не будет успевать их проглатывать (усваивать), передача будет торомозить на функции WriteFile. А если там все-таки возможна буферизация, которая спасает от ситуации, когда скорость передачи выше, чем скорость приема (или приемник глотает не непрерывно, а порциями, между которыми пауза), то будет тот же самый вариант, что и файл, отраженный на память.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Буферизация у пайпов конечно же есть.

Собственно ту часть программы что пишет в файл вообще переписывать не нужно. Просто вместо CreateFile() вызывается CreatePipe(), а функциям записи/чтения всё равно что это за хэндл, файла или пайпа, для них это без разницы.

 

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

 

А размером буфера можно управлять.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Смотри в сторону API функций:

CreateFileMapping, MapViewOfFile

Скорость записи в файл получается очень приличная.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно попробовать сделать виртуальный диск и именно там расположить файл. Это позволит не переделывать программы.

А как это можно сделать?

 

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

Я думал, что можно отображать часть файла, но похоже ошибся.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

файл целиком находится в оперативной памяти, правильно?

Под файл выделяется виртуальная память, которой не жалко. А реально существующая память будет выделяться только для тех участков файла в которые что-то писали.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Для обмена данными с помощью общей памяти используются три функции:

CreateFile - собственно создаем начальный handle, который дублируем в другой программе,

CreateFileMapping - задаем, какого размера у нас будет общая память

MapViewOfFile - создаем "окно", в которое 1-й процесс пишет, 2-й - читает...

 

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

 

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

 

Использование каналов, на мой взгляд, для данной задачи несколько удобнее, потому что вам не нужно заботиться о синхронизации - для случая с потоком, скажем, 1 мегабайт/с это вполне подойдет (если, конечно, приемник успевает "переварить" этот поток с точки зрения вычислительной трудоемкости). Кроме того, для ОС Линукс такой подход вообще стандартен - перенаправить вывод одной программы на ввод другой - например, результат поиска файлов на поиск шаблона имени а потом на программу сортировки. При этом вся буферизация/синхронизация ложится на ОС, и все работает очень эффективно - самому написать без вдумчивого анализа и большого опыта написания многопоточных программ вряд ли получится...

 

Если же потоки горазбо больше - гигабитный Ethernet фильтровать, к примеру, то, как альтернативу, предлагаю рассмотреть возможность использования MPI - ru.wikipedia.org/wiki/MPI - он изначально создавался для больших вычислительных систем с интенсивным обменом данными между различными процессами/узлами кластеров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А GetSystemInfo() говорит, что гранулярность памяти 64 Кбайта.

Пока остановился на варианте с файлами оторбражаемыми на память. Работает и, предварительно, скорость устраивает.

По поводу MPI. Спасибо за сведения! Если этот вариант не покатит - попробую!

Всем спасибо! Пока все.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...