0

WebSocket仕様の一部として、クライアントから送信されるすべてのフレームには、4バイトのマスクを使用してマスクされたフレームのペイロード部分が必要です。C ++では、これは本当に簡単です:

for (size_t i = 0; i < length; i++) {
    data[i] ^= mask[i % 4];
}

悲しいことに、Python文字列は不変であり、文字列バッファが絶えずコピーおよび再作成されるため、このようなことをする必要はありません。

frame = ''
for i in range(0, length-1):
    frame += chr(ord(oldFrame[i]) ^ ord(mask[i % 4]))

それで、いくつかの調査の後、私はこれを見つけました:

m = itertools.cycle(mask)
frame = ''.join(chr(ord(x) ^ ord(y)) for (x,y) in itertools.izip(oldFrame, m))

CPythonでは、これにより、マスキング解除に必要な時間が半分になりました。PyPyでは、16MBのマスクされた文字列の場合、これは簡単に1.5GBのRAM使用量に増加し、その後、スワップを開始し、私はそれを強制終了する必要があります。CPythonは、この16MBの文字列に「150MBのRAMのみ」を使用します(20秒かかります)が、それでも問題があります。比較すると、私のC ++ベンチマークは、メモリのオーバーヘッドなしで0.05秒でそれを実行しました。

もちろん、これらはソフトウェアが本番モードに入ると実際には発生しない極端なものです(すべての受信データは10KBに制限されています)が、このベンチマークで良いスコアを付けたいと思います。

何か案は?唯一の要件は、CPythonとPyPyの両方で高速であり、メモリ使用量が少ないことです。元の文字列を保持する必要はありません。

実験したい人のためのいくつかのテストコード:

import os, time

frame = os.urandom(16 << 20)
mask = os.urandom(4)

def unmask(oldFrame, mask):
    # Do your magic
    return newFrame

for i in range(0, 3): # Run several times, to help PyPy's JIT compiler
    startTime = time.time()
    f = unmask(frame, mask)
    endTime = time.time()
    print 'This run took %.3f seconds' % (endTime - startTime)
4

2 に答える 2

2

代わりに、変更可能なバイト配列を使用してください

frame = bytearray(frame)
for i in range(len(mask)):
    frame[i] ^= mask[i]
于 2012-11-30T11:24:17.460 に答える
0

numpyの効率的なCコードに操作をオフロードできるようにするnumpyを検討することもできます。これは、可変バイト配列をサポートする配列モジュールを使用するnumpyが使用できない場合に、websockifyが低速のメソッドへのフォールバックで使用するメソッドです。

于 2012-11-30T15:53:25.063 に答える