#python #python_3x #асинхронность #asyncio
Захотелось мне поразбираться с механизмом асинхронной работы через корунтины (сопрограммы) используя стандартную библиотеку asyncio. Написал тестовый пример и удивился тому, что асинхронный код не такой эффективный как я думал. Возможно, я неправильно работал с asyncio и есть более эффективный способ. Прошу помочь с этим вопросом. Код: from timeit import default_timer as clock from multiprocessing.dummy import Pool as ThreadPool import asyncio import hashlib def my_algo(*args): next_value = b'HELLO WORLD!' * 10000000 value = hashlib.sha1(next_value).hexdigest() next_value = bytes(value, 'utf-8') value = hashlib.sha256(next_value).hexdigest() next_value = bytes(value, 'utf-8') value = hashlib.sha512(next_value).hexdigest() next_value = bytes(value, 'utf-8') value = hashlib.md5(next_value).hexdigest() return value @asyncio.coroutine def foo(i): return my_algo(i) def my_sync(items): new_items = [] for i in items: x = my_algo(i) new_items.append(x) # print(min(new_items), max(new_items)) def my_threaded(items): pool = ThreadPool() new_items = pool.map(my_algo, items) # print(min(new_items), max(new_items)) def my_asyncio(items): ioloop = asyncio.get_event_loop() tasks = [foo(i) for i in items] wait_tasks = asyncio.wait(tasks) results = ioloop.run_until_complete(wait_tasks)[0] new_items = [x.result() for x in results] # print(min(new_items), max(new_items)) ioloop.close() if __name__ == '__main__': t = clock() print('my_algo') my_algo() print(' Elapsed:', clock() - t) print('\n') items = [1] * 100 t = clock() print('my_sync') my_sync(items) print(' Elapsed:', clock() - t) print() t = clock() print('my_threaded') my_threaded(items) print(' Elapsed:', clock() - t) print() t = clock() print('my_asyncio') my_asyncio(items) print(' Elapsed:', clock() - t) Результаты: my_algo Elapsed: 0.22824488105526344 my_sync Elapsed: 23.38838779162658 my_threaded Elapsed: 6.768628799269269 my_asyncio Elapsed: 22.96235436593546
Ответы
Ответ 1
Хэширование - это CPU-bound операция, в то время как асинхронность позволяет получить преимущество только в I/O-bound операциях. Предположим, что на всех графиках ось time - это константа. Последовательное выполнение my_algo трижды будет выглядеть так Асинхронное выполнение трёх задач, выполняющих ту же функцию my_algo так То есть это не настоящая параллельность, выполнение задач просто чередуется в том же промежутке времени. Обычно, это получается ещё и немного медленнее из-за необходимости переключения контекста. Выигрыш появился бы в том случае, если бы внутри my_algo осуществлялся ввод\вывод, блокирующий выполнение. Тогда заблокированная задача могла бы на время ожидания отдать управление другой, ещё не заблокированной. Графики взяты из "Введения в Twisted"
Комментариев нет:
Отправить комментарий