2012-02-13 10 views
13

Quiero escribir en un archivo usando un método no bloqueante en Python. En algunos google, encontré que el lenguaje admite fcntl para hacerlo, pero el método para implementar el mismo no es muy claro para mí.¿Cómo escribir en un archivo usando IO sin bloqueo?

Este es el fragmento de código (no sé donde me equivoco):

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

Es esta la forma correcta de realizar una operación de IO sin bloqueo en un archivo? Lo dudo. Además, ¿podría sugerirme algún otro módulo en Python que me permita hacerlo?

+0

posible duplicado de (http://stackoverflow.com/questions/319132/asynchronous-file-writing-possible-in-python) – jcollado

+0

[archivo de escritura asíncrona posible en Python?] No, no es así, necesito mantenerlo simple simplemente usando fcntl :) – Rahul

Respuesta

14

Esta es la forma en que encienda la no-bloqueo sobre un archivo en UNIX:

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

En UNIX, sin embargo, turning on non-blocking mode has no visible effect for regular files! Aunque el archivo esté en modo no bloqueante, la llamada os.write no se devolverá de inmediato, permanecerá inactiva hasta que se complete la escritura. Para demostrar a sí mismo de forma experimental, intente esto:

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

Se dará cuenta de que la llamada os.write embargo, toma varios segundos. Aunque la llamada no sea de bloqueo (técnicamente, no está bloqueando, está durmiendo), la llamada es no asíncrona.


AFAIK, no hay forma de escribir en un archivo de forma asincrónica en Linux o en Windows. Puede simularlo, sin embargo, usando hilos. Twisted tiene un método llamado deferToThread para este propósito. He aquí cómo lo usa:

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

¿Cómo obtendré acceso al objeto del reactor desde un LineReciver u otro protocolo similar creado por una fábrica de servidores? – Sean

+0

Se puede realizar una escritura sin bloqueo en un archivo normal con POSIX AIO o Windows IOCP. – strcat

4

Las escrituras son almacenadas en caché por el SO y vueltas al disco después de unos segundos. Es decir, ya no están "bloqueando". No tienes que hacer nada especial.

+0

¿Qué sucede si el archivo está realmente montado en un recurso compartido de red? Seguramente, la llamada solo volvería después de que se hayan recibido los reconocimientos. – Flimm

+1

Depende del sistema de archivos remoto y la semántica implementada, síncrona o asíncrona. Hay ejemplos de ambos, o incluso cosas como "sincronizar al cerrar". – jcea

Cuestiones relacionadas