Пишу копирование (фрагментов) файлов в винде, как лучше?

bastii

Задача копировать много файлов из нескольких мест, в несколько мест. Но пока интересует как это делать с одним файлом, одним источником и одним местом назначения. Файлы копируются с винтов на винты, хотелось бы это делать с максимальной скоростью.
В принципе интересует общая идея, как это делать в винде (т.е. дотнет не обязательно).
Можно, например, считать блок, записать блок и т.д. При этом наверно лучше читать и писать параллельно. Вопрос как все таки лучше это делать, и как лучше запрограммировать. Как лучше организовать потоки и буферы? Может кто экспериментировал с вводом/выводом в винде, какой размер блока для записи/чтения оптимален, каким АПИ лучше пользоваться?

otets-mihail

>какой размер блока для записи/чтения оптимален
 
попробуй наращивать размер блока, пока не достигнешь максимума =)
>каким АПИ лучше пользоваться?
native api

bastii

Найтив -- это который NtReadFile и т.д.? Это ИМХО уже изврат наверно, на недокументированные апи нет гарантии на обратную совместимость в будущих винда. Плюс ИМХО вин32 настройка довольно эффективная...
С размером конечно можно поэкспериментировать, но боюсь там все зависит от многих факторов. Хотелось бы какое-никакое общее представление иметь, исходя из которого можно оценивать какой вариант лучше.
А вообще вопросов возникает довольно много: например, создавать сразу файл необходимого размера или нет, писать через файл-меппинг или как-то еще и т.д.

otets-mihail


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

создавать сразу файл необходимого размера или нет, писать через файл-меппинг или как-то еще и т.д.
Имхо, большой выигрыш так не получить.
 
про native api я пошутил

koly

основной вопрос в размере блока чтения файла. Эта величина находится экспериментально

bastii

ты наверно экспериментировал, какими блоками получается быстрее писать/читать?
а как ты пишешь в джава: через ридеры/райтеры?

koly

Как я понял - единственный цивилизованный способ получить доступ к любой точке файла - через класс RandomAccessFile, поэтому я пользуюсь этим классом. Читаю методом readFully(byte[]).
По моим экспериментам, оптимальный размер блока - от полумегабайта до 4-6мб, но я думаю, что эти величины могут сильно колебаться в зависимости от lan и компьютеров

bastii

Такой большой? Можешь пояснить какую роль этот блок играет, т.е. как ты с ним работаешь, с лана читаешь 4мб, а потом их пишешь на диск?
Правильно я понимаю, что если проделать эксперимент, когда я в цикле пишу файл, например, размером в 200мб, блоками фиксированного размера, то получается, что оптимальным будет размер блока 4-6мб, т.е. весь файл запишется максимально быстро.

koly

Такой большой? Можешь пояснить какую роль этот блок играет, т.е. как ты с ним работаешь, с лана читаешь 4мб, а потом их пишешь на диск?
Да, сначала читаю блок, потом пишу на диск, потом снова читаю и т. д.

Правильно я понимаю, что если проделать эксперимент, когда я в цикле пишу файл, например, размером в 200мб, блоками фиксированного размера, то получается, что оптимальным будет размер блока 4-6мб, т.е. весь файл запишется максимально быстро.
Я писал, что оптимальный размер блока от полумегабайта до 4-6мб. Это лишь результат моих немногочисленных экспериментов по оценке скорости копирования.
Думаю, вот что может служить обоснованием полученных величин:
* Скорость копирования падает при увеличении частоты запросов на чтение очередного блока (т. е. , например, нельзя копировать блоками по 10 байт). Связано в основном с издержками сети
* Скорость падает при увеличении размера буфера. (например, нельзя читать фильм кусками по 100мб). Это связано с тормознутостью виртуальной памяти компьютера.
* Экстремум находится где-то посередине .
Если копировать нужно множество файлов одновременно с из нескольких источников на один приемник, то узким местом становится количество памяти на приемнике, т. к. под каждый поток по-хорошему нужно выделить память на блок чтения. Эту проблему можно решать разными способами...

bastii

О, большое спасибо. А то искал в МСДН, заглянул в Девайс ИО, а в Фаил Сервисес не заметил.

bastii

Ладно, я тут пока МСДН читаю, нужно иметь хотя бы общее представление о том, как ИО в винде устроено.
Первое, что не нравится в твоей схеме, это то, что ты читаешь и пишешь по очереди. Если я конечно правильно понял, что ты не делаешь это одновременно.
Мне всегда казалось, что в винде ИО осуществяется как последовательность элементарных запросов на ИО, поступающте запросы буферизируются в очереди, и как-то пачками обрабатываются. При этом на этом уровне не так важно, как эти запросы формировались: либо мало райтов большого размера, либо больше райтов меньшего размера. Это конечно если делать райты правильно, через какие-нибудь асинхронные АПИ. Просто когда ты делаешь синхроные райты, то конечно их реализация "хорошая" -- формируется очередь запросов на ИО, которые будут выполняются. При этом следующий синхронный райт у тебя пойдет, только после того как закончится предыдущий, т.е. когда выполнятся все его запросы на ИО. Т.о. у тебя не получается непрерывный поток запросов на ИО. В принципе, если ты пишешь большими блоками, то этот негативный эффект незначителен.
Т.о. если такое представление о ИО в винде верно, то пользуясь правильными АПИ можно иметь ту же скорость при гораздо меньших размерах блока чтения/записи. Тогда правильная реализация читает и пишет параллельно, и при этом она не нуждается в большом буфере. Большой буфер тебе нужен только для того, чтобы склаживать подтормаживания источника и назначения: если упадет скорость записи, но будет набиваться буфер на полной скорости чтения, если упадет скорость чтения, то можно на полной скорости пистать содержимое буфера.
Ладно, осталость проверить, на сколько все это соответсвует действительности.
Просто, если делать, то интересно делать это правильно

koly

Несколько раз перечитал твой пост, понял вот что:
Если я пользуюсь "обычным" api, то у меня синхронизированная запись. Но у NT есть буферезированная запись. Буферезированная запись для операций a1...an работает быстрее, чем синхронизированная для этих же кусочков. Если NT разделяет буферезированные запросы по транзакциям примерно одинаковой сложности, то использование достаточно большого буфера чтения и синхронизированного api записи не снижает скорость в сравнении с буферезированным api. Так?
Я проблему памяти на приемнике решил ограничением сверху используемой памяти: буферы чтения находятся в пуле, из которого извлекаются по необходимости и сразу возвращаются назад. Количество блоков памяти в пуле ограничено

На мой взгляд, смысл буферезированных операций есть при копировании большого числа файлов маленького размера. Но, к сожалению, я ни разу не видел действительно быстрой реализации такого копирования.
Другой вариант использования буферезированного API - очень много источников в сети, каждый из которых очень медленный, но в совокупности они дают большой траффик. В случае jdownloader - это редкая ситуация

bastii

Несколько раз перечитал твой пост, понял вот что:
Если я пользуюсь "обычным" api, то у меня синхронизированная запись. Но у NT есть буферезированная запись. Буферезированная запись для операций a1...an работает быстрее, чем синхронизированная для этих же кусочков. Если NT разделяет буферезированные запросы по транзакциям примерно одинаковой сложности, то использование достаточно большого буфера чтения и синхронизированного api записи не снижает скорость в сравнении с буферезированным api. Так?
Типа того, с учетом того, что я см плаваю в терминологии, и до конца сам не понимаю что говорю.

karkar

писать через файл-меппинг или как-то еще и т.д
Очень не рекомендую использовать мэппинг. Там с большими файлами проблемы часто бывают (которые в память не влазят сам сталкивался.

vall

эээ. какие?
или это у шарпа какие-то личные проблемы с этим?

bastii

ну наверно можно мепать кусками, не знаю, еще не пробовал
там с мепингом проблема, что скорее всего кеш забивать будет

bastii

причем здесь шарп?

karkar

Я когда-то использовал мэппинг для графического отображения wav'ов. Пока они были небольшими, все работало. Стоило же перейти на файлы, сравнимые по размеру с объемом оперативки, как пошли ошибки, не удавалось с ними также работать. Подробности сейчас не помню, ибо было это давно. Писалось на VC6 под XP.

Barbie29

заюзать gnuutils и написать шеллскрипт?

bastii

под винду?

Barbie29

http://unxutils.sourceforge.net/
мож это чем поможет...
Оставить комментарий
Имя или ник:
Комментарий: