Как записать в файл с помощью неблокирующего ввода-вывода? - PullRequest
15 голосов
/ 13 февраля 2012

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

Это фрагмент кода (я не знаю, где я ошибаюсь):

import os, fcntl
nf = fcntl.fcntl(0,fcntl.F_UNCLK)
fcntl.fcntl(0,fcntl.F_SETFL , nf | os.O_NONBLOCK )
nf = open ("test.txt", 'a') 
nf.write ( " sample text \n")

Это правильный способ выполнения неблокирующей операции ввода-вывода над файлом?Я сомневаюсь.Кроме того, не могли бы вы предложить какие-нибудь другие модули в Python, которые позволяют мне это делать?

Ответы [ 2 ]

17 голосов
/ 30 ноября 2012

Вот как вы включаете неблокирующий режим для файла в UNIX:

fd = os.open("filename", os.O_CREAT | os.O_WRONLY | os.O_NONBLOCK)
os.write(fd, "data")
os.close(fd)

В UNIX, однако, включение неблокирующего режима не имеет видимого эффекта для обычных файлов !Даже если файл находится в неблокирующем режиме, вызов os.write не будет немедленно возвращен, он будет находиться в спящем режиме до завершения записи.Чтобы доказать это экспериментально, попробуйте следующее:

import os
import datetime

data = "\n".join("testing\n" * 10 for x in xrange(10000000))
print("Size of data is %d bytes" % len(data))

print("open at %s" % str(datetime.datetime.now()))
fd = os.open("filename", os.O_CREAT | os.O_WRONLY | os.O_NONBLOCK)
print("write at %s" % str(datetime.datetime.now()))
os.write(fd, data)
print("close at %s" % str(datetime.datetime.now()))
os.close(fd)
print("end at %s" % str(datetime.datetime.now()))

Вы заметите, что вызов os.write занимает несколько секунд.Даже если вызов не является блокирующим (технически он не блокирует, он спит), вызов не асинхронный.


AFAIK, нет возможности записать вфайл асинхронно в Linux или в Windows.Однако вы можете смоделировать это, используя потоки.Для этой цели Twisted имеет метод с именем deferToThread.Вот как вы это используете:

from twisted.internet import threads, reactor

data = "\n".join("testing\n" * 10 for x in xrange(10000000))
print("Size of data is %d bytes" % len(data))

def blocking_write():
    print("Starting blocking_write")
    f = open("testing", "w")
    f.write(data)
    f.close()
    print("End of blocking_write")

def test_callback():
    print("Running test_callback, just for kicks")

d = threads.deferToThread(blocking_code)
reactor.callWhenRunning(cc)
reactor.run()
4 голосов
/ 20 февраля 2012

Записи кэшируются ОС и выводятся на диск через несколько секунд. То есть они уже "не блокируют". Вам не нужно делать ничего особенного.

...