29

背景:

我熟悉C的select()功能。我一直在将此功能用于许多目的。它们中的大多数(如果不是全部)用于读取和写入管道、文件等。我必须说我从未使用过错误列表,但这不涉及关键问题。

问题:

Python 的select()行为是否如下?

在我看来,尽管与C 的接口很简单select(),但 Python 的行为方式却有所不同。似乎在文件第一次准备好读取时返回。如果您在读取文件的同时保留一些要读取的字节,则调用将阻塞。但是,如果您在先前的调用返回后再次调用,而这两个调用之间没有任何读取调用,则将按预期返回。例如:select()select()select()select()select()select()

import select
# Open the file (yes, playing around with joysticks)
file = open('/dev/input/js0', 'r') 
# Hold on the select() function waiting
select.select([file], [], [])
# Say 16 bytes are sent to the file, select() will return.
([<open file '/dev/input/js0', mode 'r' at 0x7ff2949c96f0>], [], [])
# Call select() again, and select() will indeed return.
select.select([file], [], [])
([<open file '/dev/input/js0', mode 'r' at 0x7ff2949c96f0>], [], [])
# read 8 bytes. There are 8 bytes left for sure. Calling again file.read(8) will empty the queue and would be pointless for this example
file.read(8)
'<\t\x06\x01\x00\x00\x81\x01'
# call select() again, and select() will block
select.select([file], [], [])
# Should it block? there are 8 bytes on the file to be read.

如果这是select()Python 中的行为,我可以接受,我可以处理它。虽然不是我所期望的,但还好。我知道我能用它做什么。

但如果这不是我的行为,select()我会很感激有人告诉我我做错了什么。我读到select()的是 Python 文档所说的:“如果读|写|错误列表中的任何文件准备好读|写|错误,则 select() 返回。”。没关系,那里没有谎言。也许问题应该是:

  • 当一个文件被认为可以在 python 中读取时?
  • 这是否意味着从未读取过的文件?
  • 这是否意味着要读取字节的文件?
4

2 回答 2

20

正如您所期望的那样, Pythonselect()作为系统调用通过select(),但是您遇到的阻塞问题是另一个问题,可能与缓冲有关。只是为了满足自己select()做正确的事情,尝试在文件系统上读取/写入文件,而不是使用特殊设备,如操纵杆。

你可能想改变你的open()电话。默认情况下, Pythonopen调用将使用缓冲读取,因此即使您这样做,read(8)它也可能会从输入文件中读取更多数据并缓冲结果。您需要将该buffering选项设置为,open以便无缓冲地打开操纵杆设备。

供您尝试的建议:

  • Python 默认以文本模式打开文件。在处理诸如操纵杆之类的特殊设备时,您mode可能希望打开。rb
  • 以无缓冲模式打开文件。
  • select如果您要进行基于呼叫,请将设备设置为非阻塞模式。尝试os.open()os.O_RDONLY|os.O_NONBLOCK标志一起使用。
于 2012-07-21T10:44:18.090 回答
0

我可以问一个愚蠢的问题 - 你确定真的还剩下 8 个字节吗?

设备节点的行为不一定像普通文件。可能您必须在单个 read() 系统调用中读取整个 struct input_event。(如果你读得不够,剩下的就会被扔掉)。有点像数据报套接字上的 recvmsg()。

于 2012-07-21T10:52:25.003 回答