2012-02-13 13 views
13

Chcę napisać do pliku przy użyciu metody nieblokującej w Pythonie. W przypadku niektórych googlowań, okazało się, że język obsługuje fcntl, aby to zrobić, ale metoda realizacji tego samego nie jest dla mnie jasna.Jak pisać do pliku za pomocą niezablokowanego IO?

jest to fragment kodu (nie wiem, gdzie mam zamiar źle):

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") 

Czy to jest prawidłowy sposób przeprowadzić bez blokowania operacji IO na pliku? Wątpię. Czy mógłbyś zaproponować inne moduły w Pythonie, które mi to umożliwiają?

+0

możliwe duplikat (http://stackoverflow.com/questions/319132/asynchronous-file-writing-possible-in-python) – jcollado

+0

[Asynchronous pliku pisania możliwie w python?] Nie, nie, muszę to proste, po prostu za pomocą fcntl :) – Rahul

Odpowiedz

14

ten sposób można włączyć bez blokowania na tryb dla pliku w systemie UNIX:

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

W systemie UNIX, jednak turning on non-blocking mode has no visible effect for regular files! Mimo że plik jest w trybie bez blokowania, wywołanie os.write nie nastąpi natychmiast, będzie ono działać do momentu zakończenia zapisu. Aby udowodnić to do siebie, eksperymentalnie, spróbuj tego:

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())) 

Zauważysz, że wezwanie os.write ma potrwać kilka sekund. Mimo że połączenie nie jest blokujące (technicznie, nie blokuje, nie śpi), wywołanie jest niesynchroniczne , a nie.


AFAIK, nie ma sposobu na asynchroniczne zapisanie pliku w systemie Linux lub Windows. Możesz go jednak zasymulować za pomocą wątków. Twisted ma w tym celu metodę o nazwie deferToThread. Oto jak go używać:

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() 
+0

Jak uzyskać dostęp do obiektu reaktora z poziomu LineReciver lub innego takiego protokołu zbudowanego przez fabrykę serwerów? – Sean

+0

Zapis nie blokujący można wykonać do zwykłego pliku z POSIX AIO lub Windows IOCP. – strcat

4

Zapisy są buforowane przez system operacyjny i zrzucane na dysk po kilku sekundach. Oznacza to, że już "nie blokują". Nie musisz robić nic specjalnego.

+0

Co zrobić, jeśli plik jest rzeczywiście podłączony do udziału sieciowego? Z pewnością połączenie wróci dopiero po otrzymaniu potwierdzenia? – Flimm

+1

Zależy od zdalnego systemu plików i semantycznego zaimplementowanego, synchronicznego lub asynchronicznego. Istnieją przykłady obu, a nawet rzeczy typu "synchronizacja przy zamknięciu". – jcea

Powiązane problemy