Хорошо, так что это действительно круто, позвольте мне показать вам кое-что:
loop = asyncio.get_event_loop()
api = MyAPIToSomeCoolChatProgram()
def my_done_callback(fut):
exc = fut.exception()
if exc:
print(fut.my_custom_attribute, 'raised an exception!')
import traceback
traceback.print_exc(exc) # dumps a "Traceback (most recent call last):" message to stderr
print(fut.my_custom_attribute, 'completed, returned', repr(fut.result()))
fut1 = asyncio.ensure_future(api.send_friend_request(my_best_friend))
fut1.my_custom_attribute = 'fut1 (add a friend)'
fut1.add_done_callback(my_done_callback)
fut2 = asyncio.ensure_future(api.post_text_message('Hello everybody!'))
fut2.my_custom_attribute = 'fut2 (send a message)'
fut2.add_done_callback(my_done_callback)
print('Done creating the futures')
loop.run_forever()
Вывод:
Done creating the futures
fut1 (add a friend request) completed, returned '200 OK'
fut2 (send a message) completed, returned '200 OK'
Обратите внимание, что они могут появляться в любом порядке.Вы можете вызывать сопрограммы из не асинхронного кода, помещая сопрограмму (возвращаемое значение из функции сопрограммы) в будущем (или, точнее, Task
, который является подклассом Future
).Эта сопрограмма теперь будет работать в фоновом режиме.Вы можете добавить обратный вызов в будущее, который будет вызван после его завершения, передав один аргумент: сам объект будущего. Посмотрите на будущее в документации asyncio , если вы хотите узнать о них больше (также ознакомьтесь с Сопрограммы и задачи ).
В любом случае, эти обратные вызовы могут сделатьвсе, что вы хотите, включая запуск других задач.
def when_done_logging_in(self, fut):
self.login_info = fut.result() # note: calling fut.result() if the login coroutine raised an exception will reraise the exception here.
next_fut = asyncio.ensure_future(self.send_friend_request(fut.friend_request_to_send))
# do something with next_fut here (or don't if you don't care about the result)
def login_and_send_friend_request(self, email, friend):
fut = asyncio.ensure_future(self.query_login(email))
fut.friend_request_to_send = friend
fut.add_done_callback(self.when_done_logging_in)
Конечно, вы также можете сделать это с помощью:
async def login_and_send_friend_request(self, email, friend):
self.login_info = await self.query_login(email)
await self.send_friend_request(friend)
, что было бы лучше, потому что любые исключения действительно обрабатываются правильно, а не простоБыть игнорированным.Вы также можете сделать это, если заранее знаете адрес электронной почты (чего у вас нет):
def __init__(self, whatever_args_you_might_have_here, email):
...
self.login_info = None
self.email = email
async def send_friend_request(self, uid):
if self.login_info is None:
await self.query_login(self.email) # if you end up doing this you should probably make this not take a parameter and just use self.email instead
do_send_friend_request_stuff()
Конечно, вы можете не знать адрес электронной почты до тех пор, пока объект не будет создан, и в этом случае вы можетеИнициализируйте его как None, пока не будет вызвана какая-либо функция входа в систему, или воспользуйтесь одним из первых двух способов.
Если вы хотите последовательно выполнить список функций, вы можете сделать следующее:
def execute_coros_in_sequence(list_of_coros):
fut=asyncio.ensure_future(list_of_coros[0])
if len(list_of_coros) > 1:
# there is probably a better way to do this
fut.remaining_coros=list_of_coros[1:]
fut.add_done_callback(lambda fut: execute_coros_in_sequence(fut.remaining_coros))
но, вероятно, лучший способ сделать это - просто заставить асинхронную функцию def вызывать их все, потому что таким образом вы получите обработку исключений и т. Д. Без большого переосмысления.Лучший способ сделать это, если вы хотите, чтобы это было в будущем (которое вы также можете сохранить в качестве атрибута объекта и запроса, чтобы увидеть, сделано ли оно еще), было бы так:
class API:
async def login(self):
pass
async def logout(self):
pass
async def do_fun_stuff(self):
pass
async def test_api(api):
api.login()
api.do_fun_stuff()
api.logout()
fut=asyncio.create_task(test_part_of_api(API()))
(Кстати, asyncio.ensure_future()
сначала проверяет, является ли его аргумент уже будущим, а если нет, вызывает asyncio.create_task()
.)
, но будущий API действительно классный, и я хотел показать его вам,Есть способы его использования, и я могу в значительной степени гарантировать, что вам понадобятся оба этих подхода, чтобы сделать что-то сложное.
Извините за стену текста неорганизованного ответа.Я немного новичок здесь.Я просто думаю, что Asyncio действительно круто.