Python генерирует хэши с помощью многопроцессорной обработки

#python #python-3.x #multiprocessing

#python #python-3.x #многопроцессорная обработка

Вопрос:

У меня есть простой код, который загружает список паролей в словарь и генерирует из них хэши в новый список:

 def hash_one():
   hash_to_string = {}
   with open("wordlists/pass.txt", "r", encoding="ISO-8859-1") as file:
       for x in file:
           x = x.strip()
           result = hashlib.sha1(hashlib.sha1(x.encode()).digest()).hexdigest()
           f_result = (result)
           hash_to_string[hash] = (f_result)
           with open("hashed.txt", "a") as final:
                final.write(f_result   "n")
hash_one()
 

Интересно, как я могу использовать PoolProcessExecutor() для ускорения процесса? Теперь он читает построчно. Я пытался провести несколько тестов, но не могу заставить его работать должным образом. Я хотел бы использовать 16-ядерный процессор, который я использую.

Комментарии:

1. одновременное чтение / запись из файлов — это кошмар. Можете ли вы просто сохранить весь файл в памяти? Или, возможно, разделить файл?

2. нет необходимости, чтение / запись происходят в разных файлах. И запись — это простое добавление после основного вычисления (хеширования). Можно просто написать функцию для всего, что делается в цикле, и довольно эффективно передавать ее в пул рабочих.

3. Вы также можете увеличить скорость, не открывая выходной файл каждый раз в цикле. Есть ли причина не оставлять его открытым или сохранять результаты до конца и записывать их один раз?

4. @juanpa.arrivillaga невозможно сохранить файл в памяти, содержащий более 15 миллионов строк

5. Вы хотите ускорить чтение строк или генерацию хэшей?

Ответ №1:

Вы можете распараллелить хеширование, но на самом деле не чтение файлов. Для этого вы можете попробовать разделить исходные файлы на 16 частей и запустить свой исходный непараллельный код (запустив 16 интерпретаторов Python).

 import hashlib
import multiprocessing
from concurrent.futures import ProcessPoolExecutor

def do_hash(x):
    return hashlib.sha1(hashlib.sha1(x.encode()).digest()).hexdigest()

def hash_each_in_list(l):
    return [do_hash(x) for x in l]

def hash_each_in_list_parallel(l):
    n = multiprocessing.cpu_count()
    parts = [l[(i*len(l))//n : ((i 1)*len(l))//n] for i in range(n)]
    with ProcessPoolExecutor() as executor:
        return sum(list(executor.map(hash_each_in_list, parts)), [])

l = hash_each_in_list_parallel(open('so_2020-12-08_hashes.txt').read().splitlines())
 
 password
123456
monkey
 
 ['2470c0c06dee42fd1618bb99005adca2ec9d1e19',
    '6bb4837eb74329105ee4568dda7dc67ed2ca2ad9',
    'a5892368ae83685440a1e27d012306b073bdf5b7']
 

Непараллеленный вызов:

 l = hash_each_in_list(open('so_2020-12-08_hashes.txt').read().splitlines()))
 

Результаты теста на фиктивном файле с 10 миллионами строк, 6-ядерный процессор Ryzen 5 3600:

  • непараллеливание: 9,9 с
  • распараллеливание: 6,3 с
    • без сшивания списков в конце, используя sum(parts, []) это 5.1s

Я предполагаю, что копирование памяти здесь является узким местом, в то время как вычисление has на процессоре происходит довольно быстро, поэтому здесь нет большого ускорения. (Моя загрузка процессора не превысила 40%)