2017-10-11 5 views
0

解釈:速読、私は、次のデータフォーマットを有する巨大なバイナリファイル(数GB)を持つバイナリファイル

4後続のバイトは、から成る一つの複合データポイント(32ビット)を形成:

b0-b3 4 flag bits 
b4-b17 14 bit signed integer 
b18-b32 14 bit signed integer 

私は、符号付き整数とフラグビットの両方に別々にアクセスし、リストまたはよりスマートなデータ構造(まだ決定されていない)に追加する必要があります。現時点では私はそれを読むために、次のコードを使用しています:

from collections import namedtuple 
DataPackage = namedtuple('DataPackage', ['ie', 'if1', 'if2', 'if3', 'quad2', 'quad1']) 
def _unpack_integer(bits): 
    value = int(bits, 2) 
    if bits[0] == '1': 
     value -= (1 << len(bits)) 
    return value 


def unpack(data): 
    bits = ''.join(['{0:08b}'.format(b) for b in bytearray(data)]) 
    flags = [bool(bits[i]) for i in range(4)] 
    quad2 = _unpack_integer(bits[4:18]) 
    quad1 = _unpack_integer(bits[18:]) 
    return DataPackage(flags[0], flags[1], flags[2], flags[3], quad2, quad1) 

def read_file(filename, datapoints=None): 
    data = [] 
    i = 0 
    with open(filename, 'rb') as fh: 
     value = fh.read(4) 
     while value: 
      dp = unpack(value) 
      data.append(dp) 
      value = fh.read(4) 
      i += 1 
      if i % 10000 == 0: 
       print('Read: %d kB' % (float(i) * 4.0/1000.0)) 
      if datapoints: 
       if i == datapoints: 
        break 
    return data 

if __name__ == '__main__': 
    data = read_heterodyne_file('test.dat') 

このコードは動作しますが、それは私の目的(4バイトごとで100kのデータポイントのため2S)には遅すぎるのです。少なくとも10倍のスピードが必要です。

プロファイラでは、コードが文字列形式(ビットを取得する)と_unpack_integer()でほとんど時間を費やしていることがわかります。

残念ながら、私はここでどのように進むべきかわかりません。私はCythonを使うか、読み込みを行うためにCコードを書くことを考えています。Pypy antを試してみましたが、パフォーマンスは向上しましたが、残念ながらPypyで動作しない大きなプロジェクトと互換性がなければなりません。

+2

フォーマット設定を削除し、マスクを読み取り値に直接使用します。 「文字列をビットに変換」フェーズをスキップします。ありがとう、 –

+0

まあ、それは多くの意味があるようです。そうするためにquad2私は行データに沿って何かする必要があります= 00001111111111111100000000000000しかし、これをint16にキャストする方法がわかりません – dreichler

+0

厳密には、1 kBは** 1024 ** B(1000ではない)です。 – CristiFati

答えて

1

すでにデータ構造を認識するc/C++ライブラリがある場合は、ctypesを試してみることをおすすめします。利点は、 '読み込み'が高速である間にデータ構造があなたのPythonで引き続き利用できることです。データをロードするためのCライブラリが既にある場合は、そのライブラリからの関数呼び出しを使用して重い作業を行い、データをPython構造にマップすることができます。申し訳ありませんが、あなたの例(おそらく他の誰かの杖)を試してみることはできませんが、ここで始めるためのヒントです。 Pythonで: https://stackoverflow.com/a/40364970/262108

あなたが記述した同様の問題に私が適用した上記のアプローチ。また、Cライブラリに沿って、それを渡すことができながらここで私は、(したがって、他のPythonオブジェクトとしてオブジェクトを使用するために私を可能にする)ctypesのデータ構造を作成するためにctypesを使用しますと

https://gist.github.com/lonetwin/2bfdd41da41dae326afb

+0

それは良いヒントです、ありがとう。私はすぐにCでそれをやろうとしています。 – dreichler

1

感謝をJean-FrançoisFabreのヒント私は質問のコードと比較して第6因子のスピードアップをもたらすビットマスクを使って適切な搾汁を見つけました。現在、約300kデータポイントの群を持っています。

また、私はこれもボトルネックであることがわかったので、私は認められた名前のタプルを使用していませんでした。

コードは今

masks = [2**(31-i) for i in range(4)] 
def unpack3(data): 
    data = struct.unpack('>I', data)[0] 
    quad2 = (data & 0xfffc000) >> 14 
    quad1 = data & 0x3fff 
    if (quad2 & (1 << (14 - 1))) != 0: 
     quad2 = quad2 - (1 << 14) 
    if (quad1 & (1 << (14 - 1))) != 0: 
     quad1 = quad1 - (1 << 14) 
    flag0 = data & masks[0] 
    flag1 = data & masks[1] 
    flag2 = data & masks[2] 
    flag3 = data & masks[3] 
    return flag0, flag1, flag2, flag3, quad2, quad1 

のような行プロファイラは言う:

Line #  Hits   Time Per Hit % Time Line Contents 
============================================================== 
    58           @profile 
    59           def unpack3(data): 
    60 1000000  3805727  3.8  12.3  data = struct.unpack('>I', data)[0] 
    61 1000000  2670576  2.7  8.7  quad2 = (data & 0xfffc000) >> 14 
    62 1000000  2257150  2.3  7.3  quad1 = data & 0x3fff 
    63 1000000  2634679  2.6  8.5  if (quad2 & (1 << (14 - 1))) != 0: 
    64 976874  2234091  2.3  7.2   quad2 = quad2 - (1 << 14) 
    65 1000000  2660488  2.7  8.6  if (quad1 & (1 << (14 - 1))) != 0: 
    66 510978  1218965  2.4  3.9   quad1 = quad1 - (1 << 14) 
    67 1000000  3099397  3.1  10.0  flag0 = data & masks[0] 
    68 1000000  2583991  2.6  8.4  flag1 = data & masks[1] 
    69 1000000  2486619  2.5  8.1  flag2 = data & masks[2] 
    70 1000000  2473058  2.5  8.0  flag3 = data & masks[3] 
    71 1000000  2742228  2.7  8.9  return flag0, flag1, flag2, flag3, quad2, quad1 

だから1本の明確なボトルネックはもうありません。おそらく、純粋なPythonの場合と同じくらい速いでしょう。それとも、スピードアップを考えている人はいますか?

関連する問題