【问题标题】:python - How select.select() works?python - select.select() 如何工作?
【发布时间】:2012-07-20 10:06:23
【问题描述】:

背景:

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

问题:

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

在我看来,尽管 straightforward 与 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.

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

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

  • 何时认为文件已准备好在 python 中读取?
  • 是指一个从未被读取过的文件吗?
  • 是不是表示要读取字节的文件?

【问题讨论】:

    标签: python select


    【解决方案1】:

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

    您可能想要更改您的open() 呼叫。 Python 的open 调用默认使用缓冲读取,因此即使您执行read(8),它也可能会从输入文件中读取更多数据并缓冲结果。您需要将buffering 选项设置为open,以便无缓冲地打开操纵杆设备。

    建议您尝试:

    • Python 默认以文本模式打开文件。在处理操纵杆等特殊设备时,您可能希望打开的 moderb
    • 以非缓冲模式打开文件。
    • 如果您要进行基于select 的呼叫,请将设备设置为非阻塞模式。尝试使用 os.open()os.O_RDONLY|os.O_NONBLOCK 标志。

    【讨论】:

    • 用 0 缓冲区大小调用 open() 就可以了,这对我来说很有意义。无需将文件描述符设置为非阻塞,也无需更改读取模式。这样比较好,因为看完后需要把unpack()的字符串变成一个结构体。
    【解决方案2】:

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

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

    【讨论】:

    • @user799204,这是一个愚蠢的问题吗?你读过声明吗?是的,我确信作为示例发布的事实。让您知道这一点的唯一方法是,如果您愿意,请尝试自己。要遵循的程序是插入操纵杆,同时按下两个按钮。这会同时生成一个事件,select() 将返回。发出file.read(8) 并再次致电select() 看看我为什么提出这个问题。
    • 哦,顺便说一句,8 是特定事件的字节大小。但是,如果您愿意,您可以使用少于队列中总字节数的任何数量。查看接受的答案,缓冲是问题。
    • 抱歉我措辞不佳。我的意思是我的问题可能很愚蠢。 (它显示。struct input_event 仅适用于“事件”文件。你的 8 个字节是 struct js_event 的正确大小)。
    • 我没关系,编辑也很好。只需提及您对 UDP 数据包的看法:您是在谈论数据包丢失吗? UDP就是这样的,它没有控制传输。我不认为有人编写驱动程序,其中数据“可能”以非确定性方式丢失。或者,您可能正在谈论一个完整的队列问题。如果您的设备队列已满,旧事件将被新事件替换,所以是的,您可能会以这种方式“丢失”数据。无论如何,这不是问题。问候。
    • 我想知道您的读取大小是否太小。如果你天真地从 UDP 读取 8 个字节,而数据包是 16 个字节,那么最后 8 个字节会丢失(这反映在 MSG_TRUNC 标志中)。
    猜你喜欢
    • 2016-03-10
    • 2015-06-09
    • 2014-04-10
    • 1970-01-01
    • 2020-07-02
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多