为了账号安全,请及时绑定邮箱和手机立即绑定

md5 numpy数组的快速方法

md5 numpy数组的快速方法

慕村225694 2021-05-21 18:02:26
我正在用python 2.7中的numpy的一维数组和成千上万的uint64数字。分别计算每个数字的md5最快的方法是什么?在调用md5函数之前,每个数字都必须转换为字符串。我在很多地方都读到,遍历numpy的数组并用纯python做事情实在太慢了。有什么办法可以避免这种情况?
查看完整描述

3 回答

?
温温酱

TA贡献1752条经验 获得超4个赞

您可以为MD5()接受NumPy数组的OpenSSL函数编写包装器。我们的基准将是纯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']

对于大型阵列,速度要快15倍左右(老实说,我对此感到有些失望...)


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)


查看完整回答
反对 回复 2021-05-25
?
倚天杖

TA贡献1828条经验 获得超3个赞

我绝对建议避免转换uint64为字符串。您可以struct用来获取二进制数据,然后可以将其提供给hashlib.md5():


>>> import struct, hashlib

>>> a = struct.pack( '<Q', 0x423423423423 )

>>> a

'#4B#4B\x00\x00'

>>> hashlib.md5( a ).hexdigest()

'de0fc624a1b287881eee581ed83500d1'

>>> 

因为没有转换,只有简单的字节副本,所以这肯定会加快处理速度。


另外,hexdigest()可以将gettig替换为digest(),以返回二进制数据,这比将其转换为十六进制字符串的速度更快。根据您以后计划使用该数据的方式,这可能是一个好方法。


查看完整回答
反对 回复 2021-05-25
?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

>>> import hashlib

>>> import numpy as np

>>> arr = np.array([1, 2, 3, 4, 5], dtype="uint64")

>>> m = hashlib.md5(arr.astype("uint8"))

>>> m.hexdigest()

'7cfdd07889b3295d6a550914ab35e068'


查看完整回答
反对 回复 2021-05-25
  • 3 回答
  • 0 关注
  • 379 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号