Асинхронное программирование для вычисления хэшей файлов
Я пытаюсь вычислить хэш для файлов, чтобы проверить, были ли внесены какие-либо изменения. У меня есть Gui и некоторые другие наблюдатели, работающие в цикле событий. Итак, я решил вычислить хэш файлов [md5/Sha1, который когда-либо быстрее] асинхронно.
Синхронный код:
import hashlib
import time
chunk_size = 4 * 1024
def getHash(filename):
md5_hash = hashlib.md5()
with open(filename, "rb") as f:
for byte_block in iter(lambda: f.read(chunk_size), b""):
md5_hash.update(byte_block)
print("getHash : " + md5_hash.hexdigest())
start = time.time()
getHash("C:\\Users\\xxx\\video1.mkv")
getHash("C:\\Users\\xxx\\video2.mkv")
getHash("C:\\Users\\xxx\\video3.mkv")
end = time.time()
print(end - start)
Вывод синхронного кода: 2.4000535011291504
Асинхронный код:
import hashlib
import aiofiles
import asyncio
import time
chunk_size = 4 * 1024
async def get_hash_async(file_path: str):
async with aiofiles.open(file_path, "rb") as fd:
md5_hash = hashlib.md5()
while True:
chunk = await fd.read(chunk_size)
if not chunk:
break
md5_hash.update(chunk)
print("get_hash_async : " + md5_hash.hexdigest())
async def check():
start = time.time()
t1 = get_hash_async("C:\\Users\\xxx\\video1.mkv")
t2 = get_hash_async("C:\\Users\\xxx\\video2.mkv")
t3 = get_hash_async("C:\\Users\\xxx\\video3.mkv")
await asyncio.gather(t1,t2,t3)
end = time.time()
print(end - start)
loop = asyncio.get_event_loop()
loop.run_until_complete(check())
Вывод асинхронного кода: 27.957366943359375
я делаю это правильно? или есть какие-то изменения, которые нужно сделать, чтобы улучшить производительность кода?
Заранее спасибо.
0 ответов
В случае синхронизации вы читаете файлы последовательно. Быстрее читать файл по частям последовательно.
В случае async ваш цикл событий блокируется при вычислении хэша. Поэтому одновременно можно рассчитать только один хеш. Что означают термины "ограничение ЦП" и "ограничение ввода / вывода"?
Если вы хотите увеличить скорость вычислений, вам нужно использовать потоки. Потоки могут выполняться на ЦП параллельно. Также должно помочь увеличение CHUNK_SIZE.
import hashlib
import os
import time
from pathlib import Path
from multiprocessing.pool import ThreadPool
CHUNK_SIZE = 1024 * 1024
def get_hash(filename):
md5_hash = hashlib.md5()
with open(filename, "rb") as f:
while True:
chunk = f.read(CHUNK_SIZE)
if not chunk:
break
md5_hash.update(chunk)
return md5_hash
if __name__ == '__main__':
directory = Path("your_dir")
files = [path for path in directory.iterdir() if path.is_file()]
number_of_workers = os.cpu_count()
start = time.time()
with ThreadPool(number_of_workers) as pool:
files_hash = pool.map(get_hash, files)
end = time.time()
print(end - start)
В случае вычисления хэша только для 1 файла: aiofiles использует поток для каждого файла. ОС требуется время для создания потока.