Одинаковые результаты Asyncio и Синхронного кода
написал код, запустил, результаты примерно одинаковы:
4.6002631187438965 ----- 7.045402765274048.
Почему так, ведь, я думаю asyncio запускает всё вместе? А синхронный код в данном случае просто перебирает все по очереди.
import asyncio
from time import time
predictions = []
async def is_simple(num):
global predictions
dividers_list = []
for divider in range(1, num + 1):
if num % divider == 0:
dividers_list.append(divider)
if len(dividers_list) == 2: predictions.append([num, dividers_list])
async def starter(ranges):
tasks_list = []
for num in range(ranges):
tasks_list.append(asyncio.create_task(is_simple(num)))
await asyncio.gather(*tasks_list)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
t0 = time()
loop.run_until_complete(starter(ranges = 10000))
print(predictions)
print(time() - t0)
t0 = time()
snums = []
for element in range(10000):
slist_nums = []
for divider in range(1, element + 1):
if element % divider == 0:
slist_nums.append(divider)
if len(slist_nums) == 2:
snums.append([element, slist_nums])
print(snums)
print(time() - t0)
print(f'{len(snums)} ----- {len(predictions)}')
Ответы (2 шт):
asyncio не запускает всё вместе. Оно лишь прерывает функцию в момент ожидания await и в это время выполняет другие таски. Возвращается в функцию если ожидание завершено в момент когда другой таск прервется на await .
Чтоб ускорить Ваш код нужно использовать ProcessPoolExecutor в асинкио или обычный multiprocessing.
asyncio нужен для того чтоб выполнять таски пока что-то скачивается по сети, из базы данных или какой-то таск ждет таймера.
Во-первых саму вашу задачу можно ускорить в несколько раз, если добавить условие досрочного прерывания цикла такого вида:
if num % divider == 0:
# Если уже есть два делителя, то их будет 3
# и дальше можно уже не проверять
if len(dividers_list) >= 2:
break
dividers_list.append(divider)
Во-вторых асинхронность, как вам уже сказали в комментариях - для IO bound задач, т.е. задач, ожидающих окончания ввода-вывода. Для задач вида CPU bound, т.е. занимающихся вычислениями, как ваша задача, нужно использовать многопоточность. Хотя не факт, что в питоне это даст какой-то эффект из-за GIL, нужно проверять. И в этом случае нужно избавляться от global переменных, результат из функции нужно возвращать в явном виде и потом собирать его в список. Иначе, например, при использовании мультипроцессности, у вас не получится единый результат - у каждого процесса будет своя отдельная глобальная переменная, в которую он и добавит данные.