作为WebSocket spec的一部分,所有客户端发送的帧必须使用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的字符串“只”使用150 MB RAM相比之下,我的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)
型
3条答案
按热度按时间vatpfxk51#
使用bytearray代替,它是可变的。
字符串
ryevplcw2#
你也可以考虑numpy,它允许你将操作卸载到numpy中的高效C代码中。这是websockify使用的方法,当numpy不可用时,它会回退到一个较慢的方法,该方法使用支持可变字节数组的数组模块。
mu0hgdu03#
我发现的最快的方法是使用
translate
。我将提供Python 3的代码,但如果有人仍然使用Python 2,它应该很容易适应Python 2。字符串
下面是我的机器上的方法之间的一些比较:
1.您的原始方法排名为1.719 s,代码如下:
型
1.就地算法的排名为1.708秒:
型
1.优化它有点为您的特定usecase给出1.256 s:
型
1.相比之下,我的代码运行时间为0.034 s:
型