web-dev-qa-db-ja.com

Pythonストリームの読み取り

Pythonで終端文字列(ストリーム)を使用せずにバッファを読み取るためのvery安価な方法が必要です。これは私が持っているものですが、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」は、ターミナルエミュレータが何を解釈してもランダムな文字を大量に吐き出すため、ターミナルを破壊します(現在のシェル設定、タイトルなどを変更する可能性があります)。私はUSB経由で接続されたGPSから読んでいた。

問題:可能な場合、これはCPU使用率を100%使用します。私はこれを試しました:

#! /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のすべてのバージョンで移植可能である必要があります)であることにも注意してください。

15
dylnmc

バッファリングモードを、ファイルストリームを開くときに読み取るチャンクのサイズに設定します。 python documentation:

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 の詳細情報。

8
Anoyz

シンプルなソリューションが最適です:

_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
_

ノート:

  • ファイル記述子をブロックモードのままにしておくと、使用可能なデータがないときにOSがプロセスをブロック(およびCPU時間を節約)できます。

  • ループでイテレーターを使用することが重要です。 for line in f.readlines():を検討してください。 f.readlines()は、すべてのデータを読み取り、すべてをリストに入れて、そのリストを返します。無限のデータがあるため、f.readlines()は正常に戻りません。対照的に、fはイテレータを返します。次のループの反復を満たすために必要なだけのデータを取得します(パフォーマンスバッファの場合はもう少し)。

  • 最初のバージョンは先読みし、数行を印刷するのに十分なデータをバッファします。 2番目のバージョンは、各行をすぐに返します。 CPUの節約が主な関心事である場合は、最初のバージョンを使用してください。インタラクティブな応答時間が主な関心事である場合は、2番目を使用します。

デモンストレーション:

_$ 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
_
6
Robᵩ

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時間を節約し、あらゆる種類の良いことをする)だけでなく、明らかにバッファを非常に最新に保ちますほぼ正確に1秒間隔で結果を生成するようです(これは、ほとんどの場合と同じように、私のGPSが更新されるときです)。

クラスが真の奇跡-真の奇跡-それがこのようにそれを行う唯一の方法だった場合です。 open(file, "r")を使用するだけで問題なく動作します(これにかなりの時間を費やしたので怒りました)。

0
dylnmc