2015-12-29 2 views
7

Diese Frage - How to read from an os.pipe() without getting blocked? - zeigt eine Lösung, wie Sie überprüfen, ob os.pipe alle Daten für Linux hat, und dafür müssen Sie das Rohr in nicht-blockierenden Modus zu schalten:Nichtsperr lesen auf os.pipe auf Windows

import os, fcntl 
fcntl.fcntl(thePipe, fcntl.F_SETFL, os.O_NONBLOCK) 

Unter Windows haben wir diese:

ImportError: No module named fcntl 

Aber os.pipe gibt es:

>>> os.pipe() 
(3, 4) 

Ist es also möglich, den Inhalt von os.pipe unter Windows non-blocking zu lesen oder zu prüfen?

+1

Siehe auch http://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python (kein Duplikat, aber es gibt Überschneidungen). – ideasman42

Antwort

7

Beantworten meiner eigenen Frage nach dem Graben für einige Zeit durch StackOverflow.

UPDATE: Dinge ändert sich dank @HarryJohnston.

Zuerst die Antwort war kein, ist es nicht möglich ist, nicht blockierende lesen auf os.pipe auf Windows zu tun. Von this answer Ich habe das bekommt:

Der Begriff für nicht-blockierend/asynchronen E/A in Windows ‚überlappt‘ - das ist, was Sie betrachtend werden sollen.

os.pipe unter Windows wird durch CreatePipe API implementiert (siehe here und ... na ja, ich kann nicht os.pipe Code in Python sources finden). CreatePipe macht anonyme Rohre und anonymous pipes do not support asynchronous I/O.

Aber dann@HarryJohnston kommentierte, dass SetNamedPipeHandleState doc anonyme Pipe zu setzen, um nicht-blockierenden Modus ermöglicht. Ich schrieb den Test und es scheiterte mit OSError: [Errno 22] Invalid argument. Die Fehlermeldung schien falsch, also habe ich versucht, zu überprüfen, was Ergebnis bei nicht-blockierenden Lesevorgang sein sollte, wenn Daten nicht verfügbar sind, und nach dem Lesen MSDN note on named pipe modes fand ich, dass es ERROR_NO_DATA sein sollte, das einen Int-Wert 232 hat. Hinzufügen von ctypes.WinError() Aufruf an Exception-Handler zeigten die erwarteten [Error 232] The pipe is being closed.

So lautet die Antwort ja ist es möglich, nicht-blockierenden zu tun auf os.pipe unter Windows lesen, und hier ist der Beweis:

import msvcrt 
import os 

from ctypes import windll, byref, wintypes, GetLastError, WinError 
from ctypes.wintypes import HANDLE, DWORD, POINTER, BOOL 

LPDWORD = POINTER(DWORD) 

PIPE_NOWAIT = wintypes.DWORD(0x00000001) 

ERROR_NO_DATA = 232 

def pipe_no_wait(pipefd): 
    """ pipefd is a integer as returned by os.pipe """ 

    SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState 
    SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD] 
    SetNamedPipeHandleState.restype = BOOL 

    h = msvcrt.get_osfhandle(pipefd) 

    res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None) 
    if res == 0: 
     print(WinError()) 
     return False 
    return True 


if __name__ == '__main__': 
    # CreatePipe 
    r, w = os.pipe() 

    pipe_no_wait(r) 

    print os.write(w, 'xxx') 
    print os.read(r, 1024) 
    try: 
    print os.write(w, 'yyy') 
    print os.read(r, 1024) 
    print os.read(r, 1024) 
    except OSError as e: 
    print dir(e), e.errno, GetLastError() 
    print(WinError()) 
    if GetLastError() != ERROR_NO_DATA: 
     raise 
+0

Pipes (einschließlich anonymer Pipes) unterstützen nicht blockierende E/A zur Abwärtskompatibilität mit dem LAN-Manager. Siehe [SetNamedPipeHandleState] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365787 (v ​​= vs.85) .aspx). Aber ich habe keine Ahnung, ob Python es unterstützt. –

+0

@HarryJohnston interessant. Brauche einen Beweiscode, um zu testen, ob es wirklich funktioniert. –

+0

@HarryJohnston es funktionierte. =) Ich dachte auch, dass ich es anwenden kann, um dieses Problem https://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python zu beheben, aber stecken geblieben. Vielleicht später. –