Как вычислить несколько хэшей одновременно? - PullRequest
0 голосов
/ 03 апреля 2020

Я хочу вычислить несколько хешей одного и того же файла и сэкономить время за счет многопроцессорной обработки.

Из того, что я вижу, чтение файла из ssd относительно быстро, но вычисление sh почти в 4 раза медленнее. Если я хочу вычислить 2 разных хеша (md5 и sha), это в 8 раз медленнее. Я хотел бы иметь возможность вычислять разные хэши на разных процессорных ядрах параллельно (до 4, в зависимости от настроек), но не понимаю, как мне обойти GIL.

Вот мой текущий код (hash.py):

import hashlib
from io import DEFAULT_BUFFER_SIZE

file = 'test/file.mov' #50MG file

def hash_md5(file):
    md5 = hashlib.md5()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            md5.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return md5.hexdigest()

def hash_sha(file):
    sha = hashlib.sha1()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            sha.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return sha.hexdigest()

def hash_md5_sha(file):
    md5 = hashlib.md5()
    sha = hashlib.sha1()
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            md5.update(chunk)
            sha.update(chunk)
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return md5.hexdigest(), sha.hexdigest()

def read_file(file):
    with open(file, mode='rb') as fl:
        chunk = fl.read(DEFAULT_BUFFER_SIZE)
        while chunk:
            chunk = fl.read(DEFAULT_BUFFER_SIZE)
    return

Я провел несколько тестов и вот результаты:

from hash import *
from timeit import timeit
timeit(stmt='read_file(file)',globals=globals(),number = 100)
1.6323043460000122
>>> timeit(stmt='hash_md5(file)',globals=globals(),number = 100)
8.137973076999998
>>> timeit(stmt='hash_sha(file)',globals=globals(),number = 100)
7.1260356809999905
>>> timeit(stmt='hash_md5_sha(file)',globals=globals(),number = 100)
13.740918666999988

Этот результат должен быть функцией, основной скрипт будет перебирать список файлов и должен проверять разные хеши для разных файлов (от 1 до 4). Есть идеи, как мне этого добиться?

1 Ответ

0 голосов
/ 03 апреля 2020

Как кто-то заявил в комментариях, вы можете использовать concurrent.futures. Я сделал несколько тестов, и самый эффективный способ сделать это - использовать ProcessPoolExecutor. Вот пример:

executor = ProcessPoolExecutor(4)
executor.map(hash_function, files)
executor.shutdown()

Если вы хотите взглянуть на мои тесты, вы можете найти их здесь и результаты:

Total using read_file: 10.121980099997018
Total using hash_md5_sha: 40.49621040000693
Total (multi-thread) using read_file: 6.246223400000417
Total (multi-thread) using hash_md5_sha: 19.588415799999893
Total (multi-core) using read_file: 4.099713300000076
Total (multi-core) using hash_md5_sha: 14.448464199999762

Я использовал 40 файлов по 300 МБ каждый для тестирования.

...