1

そこで私は、マンデルブロ集合の図を作成するこのプログラムを書いています。現在、生成された各プロセスは一時ファイルにいくつかのデータを書き込みます。この一時ファイルは、後で画像をまとめるために使用されます。ただし、現在、一時ファイルは実際の画像自体よりもかなり大きいため、それらを小さくする方法については何も考えていません. 整数データをファイルに効率的に書き込んで戻すにはどうすればよいですか? 最終的にこれを非常にスケーラブルにするつもりなので、ピクセル インデックスに任意の長さの整数を書き込めるようにする必要がありますが、カラー データは常に最大値が 255 の 3 つの整数になります。これが私のコードです。

import multiprocessing

def pixproc(y0, yn, xsteps, ysteps, fname):
    XMIN, YMIN = -2., -1.
    XLEN, YLEN = 3, 2
    with open(fname, 'w') as f:
        for y in xrange(y0, yn):
            print y
            for x in xrange(xsteps):
                c=complex(XMIN + XLEN*(1.*x/xsteps),
                          YMIN + YLEN*(1.*y/ysteps))
                k=c
                for i in xrange(256):
                    k = k*k + c
                    if abs(k)>2: break
                if 0<i<32:
                    #print 'Success!', i
                    print >>f, x, y, 8*i, 0, 0 #This is that part of
                if 32<=i<255:                  #my code that I am trying
                    #print 'Success!', i       #to improve. The rest of 
                    print >>f, x, y, 255, i, i #the code is given for context
    return                                     #and isn't relevant to my question


def main(xsteps, ysteps):
    pool = multiprocessing.Pool()
    n = multiprocessing.cpu_count()
    step = height / n
    fnames = ["temp" + str(i) for i in xrange(n)]
    for i in xrange(n):
        pool.apply_async(pixproc, 
                         (step*i, 
                          step*(i+1), 
                          xsteps, 
                          ysteps, 
                          fnames[i]))
    pool.close()
    pool.join()
    return fnames


if __name__=="__main__":
    from PIL import Image
    import sys
    width, height = map(int, sys.argv[1:])
    picname = "mandelbrot1.png"
    fnames = main(width, height)
    im = Image.new("RGB", (width, height))
    pp = im.load()
    for name in fnames:
        with open(name) as f:
            for line in f:
                line = map(int, line.rstrip('\n').split(' '))
                pp[line[0], line[1]] = line[2], line[3], line[4]
    im.save(picname)

3000x2000 の画像を作成しようとすると、実際の画像は 672 KB ですが、一時ファイルは両方とも 30 MB 近くあります。誰かがデータをファイルに保存するためのより良い方法を提案できますか? (重要な部分は関数 pixproc にあります)

4

2 に答える 2

2

一時データにバイナリ形式ではなくテキストベースの形式を使用することによるオーバーヘッドを排除しようとしており、numpy を使用するようにすべてを書き直したくないと仮定すると、いくつかの異なる解決策があります。


まず、最初にデータをバイナリ形式で保持することができます:mmapファイルであり、ctypesそれを何らかの巨大なレコードとして扱うために使用します。これは通常、価値があるよりも面倒ですが、言及する価値があります。

データが 5 バイトのタプルの長いリストに過ぎないと仮定します。

class Entry(ctypes.Structure):
    _fields_ = [("x", ctypes.c_uint8), ("y", ctypes.c_uint8),
                ("i", ctypes.c_uint8), ("j", ctypes.c_uint8), ("k", ctypes.c_uint8)]
Entries = ctypes.POINTER(Entry)
with open(fname, 'wb') as f:
    f.truncate(ctypes.sizeof(Entry * (yn - y0)))
    m = mmap.mmap(f.fileno(), access=mmap.ACCESS_WRITE)

次に、 を使用できますstruct。完全な詳細についてはドキュメントを読む必要がありますが、例を 1 つ挙げます。この行を見てみましょう:

print >>f, x, y, 8*i, 0, 0

ここで、これらの 5 つすべてがバイト (0 ~ 255) であることが保証されていると仮定しましょう。あなたはただ行うことができます:

f.write(struct.pack('BBBBB', x, y, 8*i, 0, 0))

後で読み返すには:

x, y, i8, 0, 0 = struct.unpack('BBBBB', f.read(struct.calcsize('BBBBB')))
i = i8//8

それらのいずれかが 1 バイトよりも長くなる必要がある場合は、エンディアンに対処する必要がありますが、それは非常に簡単です。たとえば、x範囲yが -32768 ~ 32767 の場合:

f.write(struct.pack('>hhBBB', x, y, 8*i, 0, 0))

また、必ずファイルをバイナリ モードで開いてください。

もちろん、必要に応じてこれを と組み合わせることができmmapます。つまり、plusとplusを明示的に使用する代わりに、 struct.pack_intoandを使用できます。struct.unpack_frompackwriteunpackread


次に、pickleです。リストとそれだけを直接作成するかpickle.dump、各エントリを手動で作成し、pickle.dumpsその上に単純な上位レベルの構造を追加します (またはshelve、その上位レベルの構造がキーからエントリへの単純なマッピングである場合、またはその可能性がある場合は、 を使用します)。これは小さいどころか大きくなる可能性があり、遅くなる可能性があるため、これを検討する前に常にテストを行う必要があります。しかし、時にはそれは単純な解決策です。


str最後に、各オブジェクトの表現を単に印刷するよりも、よりコンパクトなテキスト形式を考え出すことができます。これは通常、努力する価値はありませんが、もう一度考えてみる価値はあります。

于 2013-04-09T19:55:26.430 に答える
1

モジュールを使用structして、データをバイナリ形式で書き込むことができます。

print >>f, struct.pack('@IIBBB', x, y, 8*i, 0, 0)
print >>f, struct.pack('@IIBBB', x, y, 255, i, i)

クラスを使用bz2.BZ2Fileして、圧縮ファイルを作成できます。

  with bz2.BZ2File(fname, 'w') as f:
      ...

この2つを組み合わせることもできます...

于 2013-04-09T19:43:12.667 に答える