TL; DR Kullanım asyncio.ensure_future()
aynı anda birden fazla coroutines çalıştırmak için.
Belki bu senaryo olaylar/geri aramaları yerine değiş tokuş eden kavramlar dayalı birine dayanarak bir çerçeve gerektirir? Kasırga?
Hayır, bunun için başka bir çerçeveye ihtiyacınız yoktur. Senkronize olan senkronize olmayan uygulamaların tümü, sonuç beklenirken engellenmemesidir. Koroutinler veya geri aramalar kullanılarak nasıl uygulandığı önemli değildir.
Yani, connection_handler sürekli gelen iletileri beklediği için, sunucu yalnızca istemciden bir mesaj aldıktan sonra işlem yapabilir, değil mi? Burada neyi özlüyorum? Eşzamanlı uygulamada, (aldığınız gibi) ileti alıncaya kadar tüm uygulamayı engelleyecek olan msg = websocket.recv()
gibi bir şey yazacaksınız. Ancak asenkron uygulamada tamamen farklı.
msg = yield from websocket.recv()
'u yaptığınızda şöyle bir şey söyleyebilirsiniz: connection_handler()
'un yürütmesini askıya al, websocket.recv()
bir şey üretene kadar. yield from
'un coroutine içinde kullanılması, denetim döngüsünü olay döngüsüne geri döndürür; bu nedenle, websocket.recv()
sonucunu beklerken diğer bazı kodlar çalıştırılabilir. Koroutinin nasıl çalıştığını daha iyi anlamak için lütfen documentation'a bakın.
Diyelim ki - ek olarak - bir olay meydana geldiğinde müşteriye bir mesaj göndermek istedik. Basitlik için, her 60 saniyede bir periyodik olarak bir mesaj gönderelim. Bunu nasıl yapalım?
İstediğiniz
starting event loop için engelleme çağrısı yürütmeden önce, birçok coroutines çalıştırmak için
asyncio.async()
kullanabilirsiniz.
import asyncio
import websockets
# here we'll store all active connections to use for sending periodic messages
connections = []
@asyncio.coroutine
def connection_handler(connection, path):
connections.append(connection) # add connection to pool
while True:
msg = yield from connection.recv()
if msg is None: # connection lost
connections.remove(connection) # remove connection from pool, when client disconnects
break
else:
print('< {}'.format(msg))
yield from connection.send(msg)
print('> {}'.format(msg))
@asyncio.coroutine
def send_periodically():
while True:
yield from asyncio.sleep(5) # switch to other code and continue execution in 5 seconds
for connection in connections:
print('> Periodic event happened.')
yield from connection.send('Periodic event happened.') # send message to each connected client
start_server = websockets.serve(connection_handler, 'localhost', 8000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.async(send_periodically()) # before blocking call we schedule our coroutine for sending periodic messages
asyncio.get_event_loop().run_forever()
Örnek bir istemci uygulamasıdır. Ad girmenizi, eko sunucusundan geri almanızı ister, sunucudan iki ileti daha bekler (periyodik mesajlarımız) ve bağlantıyı kapatır.
import asyncio
import websockets
@asyncio.coroutine
def hello():
connection = yield from websockets.connect('ws://localhost:8000/')
name = input("What's your name? ")
yield from connection.send(name)
print("> {}".format(name))
for _ in range(3):
msg = yield from connection.recv()
print("< {}".format(msg))
yield from connection.close()
asyncio.get_event_loop().run_until_complete(hello())
Önemli noktalar: Python 3.4.4 asyncio.async()
yılında
asyncio.ensure_future()
olarak yeniden adlandırıldı.
- delayed calls zaman planlaması için özel yöntemler vardır, ancak bunlar koroutinler ile çalışmazlar. Burada mükemmel örneğini gördüğümüz kadar
Harika cevap, teşekkürler! Koroutinlerin ne olduğunu anlıyorum, ama hala başımı asyncio çerçevesinin etrafında tutmaya çalışıyorum. Cevabınız çok yardımcı oldu. – weatherfrog