Зачем использовать Java AsynchronousFileChannel?
Я понимаю, почему сетевые приложения будут использовать мультиплексирование (чтобы не создавать слишком много потоков), и почему программы будут использовать асинхронные вызовы для конвейерной обработки (более эффективные). Но я не понимаю цели эффективности AsynchronousFileChannel.
Любые идеи?
Ответы
Ответ 1
Это канал, который вы можете использовать для чтения файлов асинхронно, т.е. операции ввода-вывода выполняются в отдельном потоке, так что поток, из которого вы его вызываете, может выполнять другие операции, в то время как операции ввода-вывода происходят.
Например: методы read()
класса возвращают объект Future
, чтобы получить результат чтения данных из файла. Итак, что вы можете сделать, это вызвать read()
, который немедленно вернется с объектом Future
. В фоновом режиме другой поток будет считывать фактические данные из файла. Ваш собственный поток может продолжать делать что-то, и когда ему нужны данные для чтения, вы вызываете get()
на объект Future
. Затем эти данные вернут данные (если фоновый поток не завершил чтение данных, он будет блокировать поток до тех пор, пока данные не будут готовы). Преимущество этого заключается в том, что вашему потоку не нужно ждать всю длину операции чтения; он может делать некоторые другие вещи, пока он действительно не нуждается в данных.
Смотрите документацию.
Обратите внимание, что AsynchronousFileChannel
будет новым классом в Java SE 7, который еще не выпущен.
Ответ 2
Я только что столкнулся с другой, несколько неожиданной причиной использования AsynchronousFileChannel. При выполнении случайных записей, ориентированных на запись, в больших файлах (превышающих физическую память, поэтому кэширование не помогает всем) в NTFS, я обнаружил, что AsynchronousFileChannel выполняет в два раза больше операций в однопоточном режиме по сравнению с обычным FileChannel.
Мое лучшее предположение заключается в том, что поскольку асинхронный io сводится к перекрытию IO в Windows 7, драйвер файловой системы NTFS может быстрее обновлять свои внутренние структуры, когда ему не нужно создавать точку синхронизации после каждого вызова.
Я микро-сравнивал с RandomAccessFile, чтобы увидеть, как он будет работать (результаты очень близки к FileChannel и еще половина производительности AsynchronousFileChannel.
Не уверен, что происходит с многопоточной записью. Это на Java 7, на SSD (SSD на порядок быстрее, чем магнитный, и на другой порядок быстрее на более мелкие файлы, которые вписываются в память).
Будет интересно посмотреть, сохраняются ли те же отношения в Linux.
Ответ 3
Основная причина, по которой я могу думать о использовании асинхронного ввода-вывода, - лучше использовать процессор. Представьте, что у вас есть приложение, которое выполняет некоторую обработку в файле. А также предположим, что вы можете обрабатывать данные, содержащиеся в файле, в кусках. Если вы не используете асинхронный ввод-вывод, ваше приложение, вероятно, будет вести себя примерно так:
- Прочитайте блок данных. Без использования процессора в этот момент, поскольку вы заблокированы, ожидая, что данные будут считаны.
- обрабатывать данные, которые вы только что прочитали. На этом этапе ваше приложение начнет потреблять циклы процессора при обработке данных.
- Если больше данных для чтения, перейдите к # 1.
Загрузка процессора будет повышаться, а затем до нуля, а затем вверх, а затем до нуля,.... В идеале вы хотите не простаивать, если хотите, чтобы ваше приложение было эффективным и обрабатывало данные как можно быстрее. Лучший подход:
- Проблема с асинхронным чтением
- Когда чтение завершено, выполните следующий асинхронный просмотр, а затем обработайте данные.
Первым шагом является перезагрузка. У вас пока нет данных, поэтому вам нужно выпустить чтение. С тех пор, когда вы получаете уведомление, прочитанное завершено, вы выдаете другое асинхронное чтение, а затем обрабатываете данные. Преимущество здесь в том, что к тому времени, как вы закончите обработку блока данных, следующее чтение, вероятно, закончилось, поэтому у вас всегда есть данные для обработки и, следовательно, вы более эффективно используете процессор. Если обработка завершится до завершения чтения, вам может потребоваться выдать несколько асинхронных чтений, чтобы у вас было больше данных для обработки.
Ник
Ответ 4
Здесь что-то никто не упомянул:
FileChannel
(поскольку он реализует InterruptibleChannel
), а также все, что его использует, например OutputStream
возвращаемый Files.newOutputStream()
, имеет неудачное поведение [1] [2], когда любая операция блокировки (например, read()
и write()
) в потоке в прерванном состоянии заставит сам Channel
закрыться с java.nio.channels.ClosedByInterruptException
.
Когда это проблема, использование AsynchronousFileChannel
вместо этого является возможной альтернативой.