Windows上os.pipe的非阻塞读取

2024-09-28 21:04:05 发布

您现在位置:Python中文网/ 问答频道 /正文

这个问题-How to read from an os.pipe() without getting blocked?-显示了一个解决方案,如何检查os.pipe是否有任何Linux数据,为此,您需要将管道置于非阻塞模式:

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

在Windows上,我们有:

ImportError: No module named fcntl

但是os.pipe有:

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

那么,是否可以在Windows上执行无阻塞读取或查看os.pipe的内容?


Tags: to数据fromanreadoslinuxwindows
1条回答
网友
1楼 · 发布于 2024-09-28 21:04:05

通过StackOverflow挖掘了一段时间后回答了我自己的问题。

更新:感谢@HarryJohnston,一切都变了。

首先,答案是否定的,在Windows上不可能进行非阻塞读取。从this answer我得到了:

The term for non-blocking / asynchronous I/O in Windows is 'overlapped' - that's what you should be looking at.

Windows上的os.pipe是通过CreatePipeAPI实现的(请参见here和。。。我在Python sources中找不到os.pipe代码。CreatePipe生成匿名管道,以及anonymous pipes do not support asynchronous I/O

但随后@HarryJohnston评论说,SetNamedPipeHandleState文档允许将匿名管道置于非阻塞模式。我写了测试,但是失败了。错误消息似乎是错误的,所以我试图在数据不可用时检查非阻塞读取操作的返回结果,在读取MSDN note on named pipe modes之后,我发现应该是ERROR_NO_DATA的int值为232。向异常处理程序添加ctypes.WinError()调用显示了预期的[Error 232] The pipe is being closed.

所以,答案是是的,在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

相关问题 更多 >