#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"
Комментариев нет:
Отправить комментарий