Answering my own question after digging for some time through StackOverflow.
UPDATE: Things changes thanks to @HarryJohnston.
At first the answer was no, it is not possible to do non-blocking read on os.pipe
on Windows. From this answer I've got that:
The term for non-blocking / asynchronous I/O in Windows is 'overlapped' - that's what you should be looking at.
os.pipe
on Windows is implemented through CreatePipe
API (see here and ... well, I couldn't find os.pipe
code in Python sources). CreatePipe
makes anonymous pipes, and anonymous pipes do not support asynchronous I/O.
But then @HarryJohnston commented that SetNamedPipeHandleState doc allows to put anonymous pipe to non-blocking mode. I wrote the test and it failed with OSError: [Errno 22] Invalid argument
. The error message seemed wrong, so I tried to check what should be return result on non-blocking read operation when data is not available, and after reading MSDN note on named pipe modes I found that it should be ERROR_NO_DATA
that has a int value 232. Adding ctypes.WinError()
call to exception handler revealed the expected [Error 232] The pipe is being closed.
So, the answer is yes, it is possible to do non-blocking read on os.pipe
on Windows, and here is the proof:
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
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…