Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
import asyncio
async def hello(name, timeout):
await poke(name, timeout)
class poke:
def __init__(self, name, timeout):
self.name = name
self.timeout = timeout
def __await__(self):
yield from asyncio.sleep(self.timeout) # say hello
if not self.name.startswith("world"):
yield from asyncio.wait([hello("world.{}".format(self.name), 0.3)])
yield
async def friends():
await asyncio.wait([
hello("friends", 0.5),
hello("neighbours", 0.3),
])
loop = asyncio.get_event_loop()
loop.run_until_complete(friends())
import time
async def hello(name, timeout):
await poke(name, timeout)
class poke:
def __init__(self, name, timeout):
self.name = name
self.timeout = timeout
def __await__(self):
time.sleep(self.timeout) # say hello
if not self.name.startswith("world"):
coro = hello("world.{}".format(self.name), 0.3)
while True:
try:
coro.send(None)
yield
except StopIteration:
break
yield
async def friends():
coros = [
hello("friends", 0.5),
hello("neighbours", 0.3)
]
for coro in coros:
coro.send(None)
for coro in coros:
await coro
poll = friends()
while True:
try:
poll.send(None)
except StopIteration:
break
import asyncio
async def hello(name, timeout):
cnt = 0
while True and cnt < 5:
await asyncio.sleep(timeout)
print("Hello, {}".format(name))
cnt += 1
if __name__ == '__main__':
tasks = [
hello("friends", 0.5),
hello("neighbours", 0.3),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
Не обижайтесь, но вы либо совсем ничего не поняли, либо ваш опыт использования кода на callback, был категорически против загрузки в голову :) материала про coroutine. Видно четко, что вы не поняли преимуществ, которые дает использование сопрограмм и пытались притянуть в примеры концепцию функций обратного вызова.
Сопрограмма созданная вызовом hello у вас завершается не успев сделать чего-то существенного, кроме ожидания своего завершения.
Зачем вы создаете и запускаете другую сопрограмму в await объекте?
Добавление «world.», может я не понял идеи. Если это для ограничение итераций, то подход абсолютно неверный — в самой короутине это можно и нужно сделать.
Функции asyncio такие как sleep, wait, etc. уже возвращают awaitable объект. Использовать с ними yield from не надо.
def friends() — это просто неоправданное увеличение энтропии :)
import asyncio
async def say(name, what, timeout):
return await poke('{} {}'.format(what, name), timeout)
async def ping(timeout):
await asyncio.sleep(timeout)
return 'OK'
async def handshake(timeout):
await asyncio.sleep(timeout)
return 'OK'
class poke:
def __init__(self, name, timeout):
self.name = name
self.timeout = timeout
def __await__(self):
res = yield from asyncio.wait_for(ping(0.1), None)
assert res == 'OK'
res = yield from asyncio.wait_for(handshake(0.1), None)
assert res == 'OK'
return 'OK'
async def invite_friends():
res, _ = await asyncio.wait([
say("friends", 'hello', 0.5),
say("neighbours", 'hello', 0.3),
])
assert all(([x.result() == 'OK' for x in res]))
loop = asyncio.get_event_loop()
loop.run_until_complete(invite_friends())
Посмотрел на ваш следующий пример и еще раз вам пишу, вы используете сопрограммы в подходе как использовали бы функции обратного вызова. Зачем? Сформулируйте мне какую задачу реализовываете в примере. Я дам свой пример, возможно это поможет разобраться. А возможно задача у вас вообще не укладывающееся в async/awaite, и пытаясь ее все же решить через coroutine вы приходите к таким странным вещам как сопрограммы делающие только то, что дожидающиеся своего завершения.
import asyncio
import logging
from random import random
logging.getLogger().setLevel(logging.DEBUG)
class dialog:
def __init__(self, name, latency):
self.name = name
self.latency = latency
async def call(self):
logging.debug('calling {}'.format(self.name))
await asyncio.sleep(self.latency/2+random())
return 'OK'
async def convince(self):
logging.debug('convincing {}'.format(self.name))
await asyncio.sleep(self.latency/2+random())
return 'OK'
def __await__(self):
res = yield from asyncio.wait_for(self.call(), None)
assert res == 'OK'
res = yield from asyncio.wait_for(self.convince(), None)
assert res == 'OK'
logging.debug('invited {}'.format(self.name))
return 'OK'
async def invite(name, latency):
return await dialog(name, latency)
async def invite_friends():
friends = [
# (name, latency)
('mark', 0.5),
('bob', 0.3),
]
coros = [invite(name, latency) for name, latency in friends]
res, _ = await asyncio.wait(coros)
assert all(([x.result() == 'OK' for x in res]))
loop = asyncio.get_event_loop()
loop.run_until_complete(invite_friends())
Почему я не могу использовать coroutines в данном примере?Я не говорил, что в этой задачи нельзя использовать coroutine, не внимательно прочитали мой ответ?
Как бы вы реализовали эту задачу?Задачу вы описали, я ее понял, и мой пример будет ниже. Теперь мне и стало понятно что у вас не так. Зачем делать логику, тем более прикладную в awaitable объекте? Он для этого не предназначен. Делайте всю логику в сопрограммах. Пример ниже, возможно многословный, но просто хотелось красивый лог:
import random
import logging
import asyncio
async def call_to(name):
cnt = 0
max_ring = 7
result = False
logging.debug("Calling {} ...".format(name))
attempts = random.randrange(0, 9, 1) + 1
while cnt < attempts:
await asyncio.sleep(1.0)
logging.debug("({}): beep".format(name))
cnt += 1
if cnt == max_ring:
logging.debug("({}): not picked up".format(name))
break
else:
result = True
return result
async def sell_on(name):
cnt = 0
max_offer = 3
logging.debug("Responding {} ...".format(name))
while True:
cnt += 1
await asyncio.sleep(1.0)
answer = random.randrange(0, 3, 1)
if answer == 2:
logging.debug("({}): Yes, I will come".format(name))
return True
elif answer == 1:
logging.debug("({}): No, I will not come".format(name))
return False
else:
if cnt == max_offer:
logging.debug("({}): No, I will not come".format(name))
return False
else:
logging.debug("({}): Maybe, I don't know".format(name))
async def invite(name, result):
answered = await call_to(name)
if answered:
agreed = await sell_on(name)
result.append((name, agreed))
else:
result.append((name, answered))
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
result = list()
frends = ['Саша', 'Паша', 'Катя', 'Маша', 'Дуся', 'Маруся', 'Ваня']
tasks = [invite(name, result) for name in frends]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print("\n----------------------------------------")
for name, agreed in result:
print("{}\t{}".format(name, "придет" if agreed else "не придет"))
loop.close()
async def sell_on(name):
cnt = 0
max_offer = 3
logging.debug("Responding {} ...".format(name))
while True:
cnt += 1
answer = random.randrange(0, 9, 1) + 1
await asyncio.sleep(answer)
if answer % 2:
logging.debug("({}): Yes, I will come".format(name))
return True
else:
logging.debug("({}): No, I will not come".format(name))
return False
Осталось только услышать ответ эксперта по поводу использования голого async/await без сторонних библиотек
Python 3.5; async/await