【问题标题】:Read file with timeout in Python在 Python 中读取超时文件
【发布时间】:2014-02-21 03:43:10
【问题描述】:

在 Linux 中,有一个文件 /sys/kernel/debug/tracing/trace_pipe,顾名思义,它是一个管道。因此,假设我想使用 Python 从中读取前 50 个字节 - 我运行以下代码:

$sudo python -c 'f=open("/sys/kernel/debug/tracing/trace_pipe","r"); print f; print f.read(50); f.close()<br>
<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb7757e90>

我们可以看到打开文件很快(如果我们有超级用户权限) - 但是,如果此时trace_pipe 文件是空的,它会简单地阻塞(即使有内容,内容也会被转储直到没有更多,然后文件将再次阻塞)。然后我必须按 Ctrl-CKeyboardInterrupt...

中断 Python 脚本

如何让 Python 2.7 进行超时读取?

也就是说,我要指示Python“尝试从这个文件中读取50个字节;如果一秒后不成功,放弃返回”

【问题讨论】:

    标签: python linux python-2.7


    【解决方案1】:

    使用

    os.read(f.fileno(), 50)
    

    相反。这不会等到读取指定数量的字节,而是在读取任何内容(最多指定数量的字节)时返回。

    如果您没有从该管道读取 nothing,这并不能解决您的问题。在这种情况下,您应该使用模块select 中的select测试是否有需要阅读的内容。

    编辑:

    使用select 测试空输入:

    import select
    r, w, e = select.select([ f ], [], [], 0)
    if f in r:
      print os.read(f.fileno(), 50)
    else:
      print "nothing available!"  # or just ignore that case
    

    【讨论】:

    • 非常感谢@Alfe - 我忘记了os.read ...但是,当我没有什么可阅读的时候,我确实想主要处理这个案子!感谢您注意到select - 但就我而言,rlistwlistxlist 是什么?如果我没有什么可读的,我应该期待什么? select 在我使用它时是否告诉我可用的总字节数,或者只是“至少有 1 个字节可用”?
    • 查看我关于select 的编辑,了解如何使用它。 select 返回您交给它的流集的子集。您的情况很简单,您只有一个只想读取的流,因此将其他所有内容都留空。将超时设置为 0,因此它永远不会等待 任何事情,然后测试是否有可以从f 读取的内容。如果是这样,至少可以读取一个字节。然后从该流中读取至少一个字节和最多 50 个字节(如您指定)。
    • 啊,您应该注意的一件事是,通常除非有阅读器读取管道,否则无法写入管道。因此,您将永远在该管道中等待读取任何内容。也许你应该使用比 0 大一点的超时时间 ;-)
    • 非常感谢@Alfe 的编辑 - 我在下面添加了一个帖子,该帖子已转换为我的用例...
    • @Alfe 这太棒了,你刚刚结束了我花费数小时的方式来掌握来自管道 bash 命令的交互式、非阻塞终端输出。谢谢!!
    【解决方案2】:
    f = os.open("/sys/kernel/debug/tracing/trace_pipe", os.O_RDONLY|os.O_NONBLOCK)
    

    应该防止阻塞(仅适用于 Unix).. 此处无需选择..

    【讨论】:

    • 非常感谢@GabiMe;不知道os.open 提供特定于平台的选项!我正在考虑将接受移到此处,但我会继续使用第一个答案,因为使用这种方法,还需要注意fdopen,如果文件中没有任何内容,还需要检查异常(请参阅我在下面的帖子中的编辑)。再次感谢 - 干杯!
    【解决方案3】:

    只需将其添加为注释,以便更好地格式化:

    @Alfe 在我的情况下的回答:

    $ sudo python -c 'import os, select; 
    f=open("/sys/kernel/debug/tracing/trace_pipe","r"); print f; 
    rrdy, wrdy, xrdy = select.select([f], [], [], 1); print rrdy, wrdy, xrdy ; 
    timeout= "timed out" if (rrdy==[]) else "" ; 
    print timeout; 
    print os.read(f.fileno(), 50) if timeout=="" else ""; 
    f.close() '
    

    如果文件中有内容,我会得到如下响应:

    <open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb76f0e90>
    [<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb76f0e90>] [] []
    
                Xorg-1033  [001] 12570.075859: <user s
    

    如果文件中没有任何内容,我会得到:

    <open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb7831e90>
    [] [] []
    timed out
    

    请注意,select 文档并未明确指出 timeout 参数以秒为单位 - 但浮点值(例如 0.5)也可以使用。

    @GabiMe 的回答:

    $ sudo python -c 'import os; 
    filno = os.open("/sys/kernel/debug/tracing/trace_pipe", os.O_RDONLY|os.O_NONBLOCK); 
    f=os.fdopen(filno, "r"); print f; 
    print "A", f.read(50); 
    print "B", os.read(f.fileno(), 50); 
    f.close() '
    

    如果文件中有内容,我会得到如下响应:

    <open file '<fdopen>', mode 'r' at 0xb77b6e90>
    A             bash-13777 [000] 13694.404519: sys_exi
    B            Timer-31065 [001] 13694.404830: sys_exi
    

    如果文件中没有任何内容,我会得到:

    <open file '<fdopen>', mode 'r' at 0xb77c1e90>
    A
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    IOError: [Errno 11] Resource temporarily unavailable
    

    ...所以必须在try 块中运行它,以捕获IOError,如果文件中没有任何内容...(os.readf.read 都会引发此异常)

    【讨论】:

    • 从您链接到的关于 select 的文档中:»可选的 timeout 参数将超时指定为以秒为单位的浮点数。« 为什么您认为它没有说明 @ 987654335@参数以秒为单位?
    猜你喜欢
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    • 2011-07-15
    相关资源
    最近更新 更多