Ответ 1
Отвечая на мой собственный вопрос после копания в течение некоторого времени через StackOverflow.
ОБНОВЛЕНИЕ. Вещи меняются благодаря @HarryJohnston.
Сначала ответ был нет, невозможно сделать неблокирующее чтение на os.pipe
в Windows. От этот ответ У меня есть это:
Термин для неблокирующего/асинхронного ввода-вывода в Windows "перекрывается" - это то, что вы должны смотреть.
os.pipe
в Windows реализован через CreatePipe
API (см. здесь и... ну, я не смог найти код os.pipe
в Источники Python). CreatePipe
делает анонимные каналы, а анонимные каналы не поддерживают асинхронный ввод-вывод.
Но затем @HarryJohnston прокомментировал, что SetNamedPipeHandleState doc позволяет помещать анонимный канал в неблокирующий режим. Я написал тест, и он не прошел с помощью OSError: [Errno 22] Invalid argument
. Сообщение об ошибке показалось неправильным, поэтому я попытался проверить, что должно быть результатом возврата при неблокирующей операции чтения, когда данные недоступны, и после чтения Заметка MSDN на именованные режимы pipe. Я обнаружил, что это должно быть ERROR_NO_DATA
, которое имеет значение int 232. Добавление ctypes.WinError()
вызов обработчику исключений показал ожидаемый [Error 232] The pipe is being closed.
Итак, ответ да, можно сделать неблокирующее чтение на os.pipe
в Windows, и вот доказательство:
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