Python读取流

时间:2014-09-30 18:44:07

标签: python filestream

我需要一种非常廉价的方法来读取Python中没有终止字符串(流)的缓冲区。这就是我所拥有的,但它浪费了很多的CPU时间和精力。因为它经常“尝试和捕捉”。我真的需要一种新方法。

以下是我的代码的简化版本:

#! /usr/bin/env/ python
import fcntl, os, sys

if __name__ == "__main__":
    f = open("/dev/urandom", "r")
    fd = f.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

    ready = False
    line = ""
    while True:
        try:
            char = f.read()
            if char == '\r':
                continue
            elif char = '\n':
                ready = True
            else:
                line += char
        except:
            continue
        if ready:
            print line

不要在终端中运行它。这只是为了说明。 “urandom”将破坏你的终端,因为它会吐出很多随机字符,终端模拟器无论解释什么(可以改变你当前的shell设置,标题等)。我正在阅读通过usb连接的gps。

问题:这可以尽可能地使用100%的CPU使用率。我试过这个:

#! /usr/bin/env/ python
import fcntl, os, sys

if __name__ == "__main__":
    f = open("/dev/urandom", "r")
    fd = f.fileno()
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

    for line in f.readlines():
        print line

但是,我得到IOError: [Errno 11] Resource temporarily unavailable。我试图在其他方面使用Popen。我很茫然。有人可以提供解决方案(请解释一切,因为我本身不是专业人士)。另外,我应该注意这是针对Unix的(特别是Linux,但它必须可以在所有版本的Linux上移植)。

3 个答案:

答案 0 :(得分:7)

您需要将缓冲模式设置为打开文件流时要读取的块的大小。 从python文档:

io.open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True)
  

" buffering 是一个可选的整数,用于设置缓冲策略。传递0以切换缓冲关闭(仅允许在二进制模式下),1选择行缓冲(仅在文本模式下可用),以及整数> 1表示固定大小的块缓冲区的大小。"

您还希望在while循环中使用readable()方法,以避免不必要的资源消耗。

但是,我建议您使用缓冲流,例如io.BytesIOio.BufferedReader

docs中的更多信息。

答案 1 :(得分:6)

简单的解决方案是最好的:

with open('/dev/urandom', 'r') as f:
    for line in f:
        print line.encode('hex')  # Don't mess up my terminal

或者,替代地

with open('/dev/urandom', 'r') as f:
    for line in iter(f.readline, ''):
        print line.encode('hex')  # Don't mess up my terminal

注意:

  • 将文件描述符保留为阻塞模式,因此当没有可用数据时,操作系统可以阻止您的进程(并节省CPU时间)。

  • 在循环中使用迭代器很重要。考虑for line in f.readlines():f.readlines()读取所有数据,将其全部放入列表中,然后返回该列表。由于我们有无限的数据,f.readlines()永远不会成功返回。相反,f返回一个迭代器 - 它只获得满足下一个循环迭代所需的数据(对于性能缓冲区只需多一点)。

  • 第一个版本预读并缓冲足够的数据以打印多行。第二个版本立即返回每一行。如果节省CPU是您主要关注的问题,请使用第一个版本。如果主要关注的是交互响应时间,请使用第二个。

演示:

$ python x.py  | head -2l
eb99f1b3bf74eead42750c63cb7c16160fa7e21c94b176dc6fd2d6796a1428dc8c5d15f13e3c1d5969cb59317eaba37a97f4719bb3de87919009da013fa06ae738408478bc15c750850744a4edcc27d155749d840680bf3a827aafbe9be84e7c8e2fe5785d2305cbedd76454573ca9261ac9a480f71242baa94e8d4bdf761705a6a0fea1ba2b1502066b2538a62776e9165043e5b7337d45773d009fd06d15ca0d9b51af499c1c9d7684472272a7361751d220848874215bc494456b08910e9815fc533d3545129aad4f3f126dc5341266ca4b85ea949794cacaf16409bcd02263b08613190b3f69caa68a47758345dafb10121cfe6ed6c8098142682aef47d1080bd2e218b571824bf2fa5d0bb5297278be8a9a2f55b554631c99e5f1d9040c5bc2bde9a40c8b6e95fc47be6ea9235243582f2367893d15a1494f732d0346ec6184a366f8035aef9141c638128444b1549a64937697b1a170e648d20f336e352076893fa7265c8fa0f4e2207e87410e53b43a51aa146ac6c2decf274a45a58c4e442aececf28879a3e0b4a1278eac7a4f969b3f74e2f2a2064a55ff112c4c49092366dbaa125703962ec5083d09cdb750c0e1dbe34cadda66709f98ff63faccf0045993137bfaca949686bc395bbafb7cf9b5b3475a0c91bdea8cec4e9ac1a9c96e0b81c1c5f242ae72cdea4c073db0351322f9da31203ea34d1b6f298128435797f4846a53b0733069060680dbc2b44c662c4b685ced5419b65c01df41cc2dd9877dc2a97a965174d508a3c9275d8aee7f2991bbb06ca7e0010b0e5b9468aed12f5d2c9a65091223547b8655211df435ffbf24768d48c7e7cf3cb7225f2c116e94a8602078f2b34dab6852f57708e760f88f4085ec7dade19ed558a539f830adea1b81f46303789224802f1f090ec0ff59e291246f1287672b0035df07c359d2ada48e674622f61c0f456c36d130fb6cf7f529e7c4dfceccc594ba5e812a3250e022eca9576a5a8b31c0be13969841d5a4d52b10a7dc8ddd1cac279500cb66e3b244e7d1e042249fd8adf2a90fa8bee74378d79a3d55c6fcf6cc19aa85ffb078dba23ca88ea6810d4a1c5d98b3b33e68ddd41c881df167c36ab2e1b081849781e08e3a026fbd3755acf9f215e0402cbf1a021300f5c883f86a05d467479172109a8f20f93c8c255915a264463eb113c3e8d07d0cec31aa8c0f978a0e7e65c142e85383befd6679c69edd2c56599f15580bbb356d98cfdf012dbc6d1dd6c0dbcfe6f8235d3d5c015fb94d8cc29afdf5d69e33d0e5078d651782546bc2acccab9f35e595f0951a139526ae5651a3ebbec353e99f9ddd1615ed25529500dabe8bf6f12ee6b21a437caca12a6d9688986d94fb7c103dca1572350900e56276b857630a
9d024ef4454dcd5e35dd605a2d49c26ce44fae87ab33e7a158d328521c7d77969908ec5b67f01bf8e2c330dcb70b5f3def8e6d4b010c6d31e4cbe7478657782f10b6fc2d77e8ff7a2f1e590827827e1037b33b0a
Traceback (most recent call last):
  File "x.py", line 4, in <module>
    print line.encode('hex')  # Don't mess up my terminal
IOError: [Errno 32] Broken pipe

答案 2 :(得分:0)

我决定使用io。我注意到这比while True:更准确。我正在阅读的gps应该每秒吐出信息,但我注意到它确实在0.95到1.05秒之间。那时我正在做我在问题中发布的内容。

然而,当我只是做

#! /usr/bin/env/ python

import io

if __name__ == "__main__":
    f = io.open("/dev/ttyUSB0")
    while True:
        print f.readline().strip()

它不仅暂时阻止(它节省了cpu时间,并且做了各种好事),但它显然也使缓冲区保持最新状态,因为它似乎几乎只产生一秒钟的结果分开(这是我的gps - 像大多数人一样 - 更新)。

这是一个真正的奇迹 - 一个真正的奇迹 - 即如果它是这样做的唯一方法。一个人可以使用open(file, "r"),它运行正常(这让我感到愤怒,因为我花了整整一天时间)。