Конец неблокирующего файла - PullRequest
19 голосов
/ 13 апреля 2011

Как определяется конец файла для файла в неблокирующем режиме?

Ответы [ 5 ]

14 голосов
/ 05 мая 2011

По крайней мере в POSIX (включая Linux) очевидный ответ заключается в том, что обычные неблокирующие файлы не существуют. Обычные файлы ВСЕГДА блокируются, а O_NONBLOCK молча игнорируется.

Аналогично, poll () / select () et al. всегда сообщит вам, что fd, указывающий на обычный файл, готов к вводу / выводу, независимо от того, готовы ли данные в кеше страницы или еще на диске (в основном релевантны для чтения).

EDIT И, поскольку O_NONBLOCK не используется для обычных файлов, read () для обычного файла никогда не установит errno в EAGAIN, в отличие от того, что утверждает другой ответ на этот вопрос.

РЕДАКТИРОВАТЬ2 Ссылки:

В спецификации POSIX (p) выберите () : «Файловые дескрипторы, связанные с обычными файлами, должны всегда выбирать true для условий готовности к чтению, готовности к записи и ошибок».

Из спецификации POSIX poll () : «Обычные файлы всегда должны опрашивать ИСТИНА для чтения и записи».

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

Помимо вышесказанного, есть хотя бы некоторые косвенные доказательства

Из спецификации POSIX open () : Определяется поведение файловых дескрипторов, относящихся к каналам, блочным специальным файлам и символьным специальным файлам. «В противном случае поведение O_NONBLOCK не определено.»

Некоторые ссылки по теме:

http://tinyclouds.org/iocp-links.html

http://www.remlab.net/op/nonblock.shtml

http://davmac.org/davpage/linux/async-io.html

И даже здесь, на stackoverflow:

Может ли обычное чтение файлов получить пользу от неблокирующего ввода-вывода?

Как указывает ответ Р., из-за того, как работает кэширование страниц, неблокирование обычных файлов не очень легко определить. Например. Что если по какому-то механизму вы обнаружите, что данные готовы для чтения в кеше страниц, а затем, прежде чем читать, ядро ​​решает выкинуть эту страницу из кеша из-за нехватки памяти? Это отличается для таких вещей, как сокеты и каналы, потому что правильность требует, чтобы данные не отбрасывались просто так

Кроме того, как бы вы выбрали / опросили для поиска дескриптора файла? Вам понадобится новый API, который будет поддерживать указание диапазона байтов в интересующем вас файле. И реализация этого API в ядре будет привязана к системе VM, так как это предотвратит интересующие вас страницы. быть выгнанным Что означало бы, что эти страницы будут учитываться при ограничении заблокированных страниц процесса (см. Ulimit -l), чтобы предотвратить DOS. И когда эти страницы будут разблокированы? И так далее.

5 голосов
/ 13 апреля 2011

Это действительно хороший вопрос.Неблокирующие сокеты возвращают пустую строку из recv() вместо броска socket.error, указывающего, что нет доступных данных.Для файлов, тем не менее, нет никакого прямого индикатора, доступного для Python.

Единственный механизм обнаружения EOF, который я могу придумать, - это сравнить текущую позицию файла с общим размером файла после получения пустой строки:

def read_nonblock( fd ):
    t = os.read(fd, 4096)
    if t == '':
        if os.fstat(fd).st_size == os.lseek(fd, 0, os.SEEK_CUR):
            raise Exception("EOF reached")
    return t

Это, конечно,Предполагается, что обычные файлы в неблокирующем режиме будут возвращаться немедленно, а не ждать, пока данные будут считаны с диска.Я не уверен, правда ли это на Windows или Linux.Было бы полезно протестировать, но я не удивлюсь, если чтение обычных файлов даже в неблокирующем режиме вернет пустую строку только при обнаружении фактического EOF.

1 голос
/ 11 мая 2011

Для файлов установка дескриптора файла как неблокирующего ничего не делает - все операции ввода-вывода все равно блокируются.

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

Опять же, может быть, вы заинтересованы в том, чтобы каким-то образом "выбрать" файл, такой, чтобы вы получали уведомление о его росте. Как вы, наверное, поняли select, poll и т. Д. Не работают. Большая часть программного обеспечения делает это просто, опрашивая файл каждую секунду или около того - например, "tail -f" делает свое дело, опрашивая. Тем не менее, вы также можете заставить ядро ​​уведомлять вас, когда файл записывается - и это происходит с inotify и друзьями. Есть несколько удобных библиотек, оборачивающих все это для вас, так что вам не придется самим разбираться со спецификой. А именно, для питона inotifyx и pyinotify.

1 голос
/ 08 мая 2011

Не говорит ли вам, что есть что почитать, даже если это просто EOF? Если он говорит вам, что есть что почитать, а вы ничего не получаете обратно, значит, это EOF. Я считаю, что это относится к сокетам.

1 голос
/ 05 мая 2011

Хорошая уловка, которая хорошо работает в c ++ (YMMV), заключается в том, что если объем возвращаемых данных меньше размера буфера (т.е. буфер не заполнен), вы можете смело предполагать, что транзакция завершена. тогда существует вероятность 1 / buffersize, что последняя часть файла полностью заполняет буфер, так что для большого размера буфера вы можете быть уверены, что транзакция закончится с незаполненным буфером, и поэтому, если вы протестируете количество данных Возвращается в зависимости от размера буфера, и они не равны. Вы знаете, что произошла ошибка или транзакция завершена. Не уверен, переведется ли это на python, но это мой метод определения EOF

...