栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

简单的Python挑战:数据缓冲区上最快的按位异或

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

简单的Python挑战:数据缓冲区上最快的按位异或

第一次尝试

使用

scipy.weave
和SSE2内在函数会带来一点改进。第一次调用要慢一些,因为需要从磁盘加载代码并进行缓存,随后的调用会更快:

import numpyimport timefrom os import urandomfrom scipy import weaveSIZE = 2**20def faster_slow_xor(aa,bb):    b = numpy.fromstring(bb, dtype=numpy.uint64)    numpy.bitwise_xor(numpy.frombuffer(aa,dtype=numpy.uint64), b, b)    return b.tostring()pre = """const __m128i* pa = (__m128i*)a;const __m128i* pend = (__m128i*)(a + arr_size);__m128i* pb = (__m128i*)b;__m128i xmm1, xmm2;while (pa < pend) {  xmm1 = _mm_loadu_si128(pa); // must use unaligned access   xmm2 = _mm_load_si128(pb); // numpy will align at 16 byte boundaries  _mm_store_si128(pb, _mm_xor_si128(xmm1, xmm2));  ++pa;  ++pb;}"""def inline_xor(aa, bb):    a = numpy.frombuffer(aa, dtype=numpy.uint64)    b = numpy.fromstring(bb, dtype=numpy.uint64)    arr_size = a.shape[0]    weave.inline(pre, ["a", "b", "arr_size"], headers = ['"emmintrin.h"'])    return b.tostring()

第二次尝试

考虑到注释,我重新检查了代码,以查明是否可以避免复制。原来我读错了字符串对象的文档,所以这是我的第二次尝试:

support = """#define ALIGNMENT 16static void memxor(const char* in1, const char* in2, char* out, ssize_t n) {    const char* end = in1 + n;    while (in1 < end) {       *out = *in1 ^ *in2;       ++in1;        ++in2;       ++out;    }}"""pre2 = """PyObject* res = PyString_FromStringAndSize(NULL, real_size);const ssize_t tail = (ssize_t)PyString_AS_STRING(res) % ALIGNMENT;const ssize_t head = (ALIGNMENT - tail) % ALIGNMENT;memxor((const char*)a, (const char*)b, PyString_AS_STRING(res), head);const __m128i* pa = (__m128i*)((char*)a + head);const __m128i* pend = (__m128i*)((char*)a + real_size - tail);const __m128i* pb = (__m128i*)((char*)b + head);__m128i xmm1, xmm2;__m128i* pc = (__m128i*)(PyString_AS_STRING(res) + head);while (pa < pend) {    xmm1 = _mm_loadu_si128(pa);    xmm2 = _mm_loadu_si128(pb);    _mm_stream_si128(pc, _mm_xor_si128(xmm1, xmm2));    ++pa;    ++pb;    ++pc;}memxor((const char*)pa, (const char*)pb, (char*)pc, tail);return_val = res;Py_DECREF(res);"""def inline_xor_nocopy(aa, bb):    real_size = len(aa)    a = numpy.frombuffer(aa, dtype=numpy.uint64)    b = numpy.frombuffer(bb, dtype=numpy.uint64)    return weave.inline(pre2, ["a", "b", "real_size"],   headers = ['"emmintrin.h"'],   support_pre = support)

区别在于字符串是在C代码内部分配的。不可能按照SSE2指令的要求将其对齐在16字节的边界上,因此,使用字节访问来复制开头和结尾未对齐的内存区域。

无论如何,使用numpy数组传递输入数据,因为

weave
坚持将Python
str
对象复制到
std::string
s。
frombuffer
不会复制,因此很好,但是内存未对齐16字节,因此我们需要使用
_mm_loadu_si128
而不是更快的
_mm_load_si128

而不是使用

_mm_store_si128
,而是使用
_mm_stream_si128
,它可以确保所有写入均尽快流式传输到主内存中-
这样,输出数组不会耗尽宝贵的缓存行。

时机

至于时间安排,

slow_xor
第一次编辑中的条目指的是我的改进版本(内联按位xor,
uint64
),我消除了这种混乱。
slow_xor
指的是来自原始问题的代码。所有计时都完成了1000次运行。

  • slow_xor
    :1.85秒(1倍)
  • faster_slow_xor
    :1.25s(1.48x)
  • inline_xor
    :0.95秒(1.95倍)
  • inline_xor_nocopy
    :0.32s(5.78x)

该代码是使用gcc 4.4.3编译的,我已经验证了编译器实际上使用了SSE指令。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/449405.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号