代码之家  ›  专栏  ›  技术社区  ›  Frederico Schardong

快速实现md5的numpy阵列

  •  0
  • Frederico Schardong  · 技术社区  · 6 年前

    在python2.7中,我正在使用一个numpy的1d数组,其中包含数千个uint64数字。计算每个数字的md5最快的方法是什么?

    在调用md5函数之前,每个数字都必须转换为字符串。我在很多地方读到过,迭代numpy的数组和用纯python做事情非常慢。有什么办法可以避免吗?

    0 回复  |  直到 6 年前
        1
  •  6
  •   Nils Werner    5 年前

    您可以为OpenSSL的 MD5() 接受NumPy数组的函数。我们的基线将是一个纯Python实现。

    使用cffi创建包装器:

    import cffi
    
    ffi = cffi.FFI()
    
    header = r"""
    void md5_array(uint64_t* buffer, int len, unsigned char* out);
    """
    
    source = r"""
    #include <stdint.h>
    #include <openssl/md5.h>
    
    void md5_array(uint64_t * buffer, int len, unsigned char * out) {
        int i = 0;
        for(i=0; i<len; i++) {
            MD5((const unsigned char *) &buffer[i], 8, out + i*16);
        }
    }
    """
    
    ffi.set_source("_md5", source, libraries=['ssl'])
    ffi.cdef(header)
    
    if __name__ == "__main__":
        ffi.compile()
    

    import numpy as np
    import _md5
    
    def md5_array(data):
        out = np.zeros(data.shape, dtype='|S16')
    
        _md5.lib.md5_array(
            _md5.ffi.from_buffer(data),
            data.size,
            _md5.ffi.cast("unsigned char *", _md5.ffi.from_buffer(out))
        )
        return out
    

    并将两者进行比较:

    import numpy as np
    import hashlib
    
    data = np.arange(16, dtype=np.uint64)
    out = [hashlib.md5(i).digest() for i in data]
    
    print(data)
    # [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15]
    print(out)
    # [b'}\xea6+?\xac\x8e\x00\x95jIR\xa3\xd4\xf4t', ... , b'w)\r\xf2^\x84\x11w\xbb\xa1\x94\xc1\x8c8XS']
    
    out = md5_array(data)
    
    print(out)
    # [b'}\xea6+?\xac\x8e\x00\x95jIR\xa3\xd4\xf4t', ... , b'w)\r\xf2^\x84\x11w\xbb\xa1\x94\xc1\x8c8XS']
    

    data = np.arange(100000, dtype=np.uint64)
    
    %timeit [hashlib.md5(i).digest() for i in data]
    169 ms ± 3.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %timeit md5_array(data)
    12.1 ms ± 144 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
        2
  •  1
  •   lenik    5 年前

    我绝对建议避免转换 uint64 到字符串。你可以用 struct hashlib.md5() :

    >>> import struct, hashlib
    >>> a = struct.pack( '<Q', 0x423423423423 )
    >>> a
    '#4B#4B\x00\x00'
    >>> hashlib.md5( a ).hexdigest()
    'de0fc624a1b287881eee581ed83500d1'
    >>> 
    

    还有,盖蒂 hexdigest() 可替换为 digest() ,返回二进制数据,比将其转换为十六进制字符串更快。根据您以后打算如何使用这些数据,这可能是一个好方法。

        3
  •  -1
  •   user2874583    5 年前

    您可以应用一个将函数映射到数组上的函数。这是这里最容易做的事。 link

    在这个示例中,我只向原始数组中添加1。您可以在这里根据需要对MD5进行转换。

    import numpy as np
    x = np.array([1, 2, 3, 4, 5])
    f = lambda x: x + 1
    result = f(x)