2009-07-02 14 views
5

Ich habe eine Frage über freigegebene Ressource mit Dateizugriff zwischen Prozessen. Hier ist mein Testcode:Freigabe von Objekten mit Datei-Handle-Attribut zwischen Prozessen

from multiprocessing import Process,Lock,freeze_support,Queue 
import tempfile 
#from cStringIO import StringIO 

class File(): 
    def __init__(self): 
     self.temp = tempfile.TemporaryFile() 
     #print self.temp 

    def read(self): 
     print "reading!!!" 
     s = "huanghao is a good boy !!" 
     print >> self.temp,s 
     self.temp.seek(0,0) 

     f_content = self.temp.read() 
     print f_content 

class MyProcess(Process): 
    def __init__(self,queue,*args,**kwargs): 
     Process.__init__(self,*args,**kwargs) 
     self.queue = queue 

    def run(self): 
     print "ready to get the file object" 
     self.queue.get().read() 
     print "file object got" 
     file.read() 

if __name__ == "__main__": 
    freeze_support() 
    queue = Queue() 
    file = File() 

    queue.put(file) 
    print "file just put" 

    p = MyProcess(queue) 
    p.start() 

Dann bekomme ich ein KeyError wie unten:

file just put 
ready to get the file object 
Process MyProcess-1: 
Traceback (most recent call last): 
    File "D:\Python26\lib\multiprocessing\process.py", line 231, in _bootstrap 
    self.run() 
    File "E:\tmp\mpt.py", line 35, in run 
    self.queue.get().read() 
    File "D:\Python26\lib\multiprocessing\queues.py", line 91, in get 
    res = self._recv() 
    File "D:\Python26\lib\tempfile.py", line 375, in __getattr__ 
    file = self.__dict__['file'] 
KeyError: 'file' 

Ich denke, wenn ich die File() in Warteschlange Objekt setzen, das Objekt bekam serialisiert und Datei-Handle kann nicht serialisiert werden, also, ich habe die KeyError:

Wer hat eine Idee dazu? Wenn ich Objekte mit dem Dateizugriffsattribut teilen möchte, was soll ich tun?

Antwort

7

Ich muss widersprechen (ausführlich, passt nicht nur in einen Kommentar ;-) @ Marks wiederholte Behauptung, dass Dateihandles einfach nicht zwischen laufenden Prozessen "herumgereicht werden können" - das ist einfach nicht wahr in echten, modernen Betriebssystemen, wie zum Beispiel Unix (kostenlose BSD-Varianten, MacOSX und Linux, enthalten - hmmm, ich frage mich, welche Betriebssysteme sind aus dieser Liste weggelassen ...? -) - sendmsg von Natürlich kann es (auf einem "Unix-Socket", indem Sie die SCM_RIGHTS Flagge) tun.

Jetzt ist das arme, wertvolle multiprocessing völlig richtig, diese Eigenschaft nicht auszunutzen (selbst vorausgesetzt, es könnte schwarze Magie sein, es unter Windows auch zu implementieren) - die meisten Entwickler würden es zweifellos trotzdem missbrauchen (mehrere Prozesse haben denselben Zugriff) Datei gleichzeitig öffnen und in Rennbedingungen laufen). Die einzige geeignete Methode ist die Verwendung eines Prozesses mit exklusiven Rechten zum Öffnen bestimmter Dateien, um die geöffneten Dateizugriffsnummern an einen anderen Prozess zu übergeben, der mit eingeschränkten Berechtigungen ausgeführt wird. Verwenden Sie dieses Handle dann nie wieder selbst. Es gibt keine Möglichkeit, dies im Modul multiprocessing zu erzwingen.

Zurück zu @Dy's ursprünglicher Frage, außer er wird nur mit Linux arbeiten (UND nur mit lokalen Prozessen) und bereit sein, schmutzige Tricks mit dem/proc-Dateisystem zu spielen, er muss seine Anwendungsebene definieren benötigt schärfer und serialisieren file Objekte entsprechend. Die meisten Dateien haben einen Pfad (oder können gemacht werden, um einen zu haben: Pfadlose Dateien sind ziemlich selten, tatsächlich nicht existent unter Windows, glaube ich) und können daher über sie serialisiert werden - viele andere sind klein genug, um sie zu serialisieren Inhalt über - etc, etc.

+0

Ich denke, was ich sagen wollte (dies zumindest die zweite Korrektur) war Datei * descriptor * - wo Sie in der Regel eine Zahl> = 3 erhalten (wegen 0,1, 2 ist reserviert für std {in, out, err}). Wenn Sie also eine Datei öffnen und der Deskriptor 3 lautet, ist die Weitergabe von 3 an einen anderen Prozess bedeutungslos. Habe ich es endlich geschafft? –

+0

vielen dank, Alex! Also, wie Sie gesagt haben, ist es sehr schwer, wenn ich Dateigriffe zwischen Prozessen auf Windows übergeben möchte. Wenn ich Dateien weitergeben möchte, sollte ich den Dateipfad oder den Inhalt der Datei übergeben, nicht Dateigriffe. – Ryan

+0

@Mark, nicht wirklich, es ist in der Tat die '3' müssen Sie übergeben ... nur an einem AF_UNIX-Socket und mit dem SCM_RIGHTS-Flag (der Kernel wird den Rest der benötigten Magie tun: die Nummer, die ankommt, kann wahrscheinlich sein! = 3, aber es wird ein Deskriptor für die gleiche offene Datei sein). Solaris hat einen saubereren Weg, wenn ich mich recht erinnere, und tatsächlich mehrere syscalls, um richtig mit dem Problem umzugehen (aber es ist zu lange her, dass ich tatsächlich an Solaris gearbeitet habe, Seufz, ich erinnere mich nicht scharf). –

Verwandte Themen