Async ve await deyimleri tam olarak ne anlama geliyor?


#1

Arkadaşlar merhaba,
uzun zamandır pythonla haşır neşirim ama bugün bir modülü öğrenmem gerekti, websockets ancak belgelerine bakarken ilk defa async ve await deyimlerini gördüm, kullanımı şöyle:
#!/usr/bin/env python

import asyncio
import websockets

async def hello(websocket, path):
    name = await websocket.recv()
    print("< {}".format(name))

    greeting = "Hello {}!".format(name)
    await websocket.send(greeting)
    print("> {}".format(greeting))

start_server = websockets.serve(hello, 'localhost', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

bilen biri varsa bana açıklayabilir mi?şimdiden çok teşekkürler.


#2

Merhaba.

async / await diğer programlama dillerinde de yer alan ya da alacak olan genel bir kavramdır. Bir fonksiyonu/metodu async ile belirttiğinizde fonksiyona, asenkron yani ana akıştan bağımsız çalışabilecek bir fonksiyondur anlamı kazandırırsınız. Genelde örnekte verdiğiniz gibi ağla ilgili işlemler yapan ya da giriş/çıkış işlemleri yapan fonksiyonlarda kullanılırlar.

async fonksiyon/metodlar kod akışını takip etmeyecekleri yani kod akışına paralel çalışabilecekleri için bu fonksiyonları/metodları await sözcüğü kullanarak bekletebilirsiniz.

Kodlarınızdan örnek verecek olursak hello, websocket.recv ve websocket.send birer async fonksiyondur. Örneğin; name = await websocket.recv() satırını await olmadan yazarsanız, yorumlayıcı bu satırın sonucunu beklemeden bir sonraki satırdaki kodu çalıştırır ve name değişkeninin tanımlı olmadığını görürsünüz (Deneyebilirsiniz.).

Yani kısaca async / await asenkron(eşzamansız) kodlarla uğraşmak için thread’lerden çok daha iyi bir yol sunan modern bir kavramdır.


#3

Merhaba İsmail Bey,
Cevabınız için çok teşekkür ederim, bu konuda aydınlanmış oldum.
Saygılarımla,

ek bilgi:
http://mehmetkose.github.io/aiohttp-ile-1-milyon-asenkron-istek-yapmak.html


#4

Merhaba, socket modülüyle yeni yeni ilgilendiğim zamanlarda, kullanıcılar cevap almayı beklemeden nasıl mesaj gönderebilirler diye düşünürken, birisi bana ya threading modülünü ya da asyncio modülünü kullanmamı söylemişti. Hatta sağolsun asyncio ile ilgili örnek bir sunucu-istemci uygulaması paylaşmıştı. Ben de müsadenizle burada belki ilgilisinin işine yarayabilir, örnek bolluğu olsun diyerek paylaşmak istiyorum:

server.py

import asyncio
import aioconsole


class StreamWrapper(object):
    """This class is used to make socket stream created by server available for send_messgaes() function"""

    def __init__(self):
        self.reader = None
        self.writer = None


async def send_messages(stream_wrapper, stdin):
    # Wait asynchronously until server part initializes socket stream
    while stream_wrapper.writer is None:
        await asyncio.sleep(0.1)
    writer = stream_wrapper.writer
    # Asynchronusly read from standard input
    async for message in stdin:
        if message.decode().strip() == "q":
            writer.close()
            exit()
        else:
            # Send message through the socket
            writer.write(message)


def receive_messages_wrapper(stream_wrapper, stdout):
    """Wrapper function which adds stream_wrapper and stdout to the scope of receive_messages()"""
    async def receive_messages(reader, writer):
        # Copy socket stream reference to stream wrapper
        stream_wrapper.reader = reader
        stream_wrapper.writer = writer
        # Asynchronusly read messages from the socket
        async for message in reader:
            stdout.write('\nClient: {}'.format(message.decode()))
            stdout.write("Server: ")
    # Wrapper returns receive_messages function with enhanced scope - receive_messages() can "see"
    # stream_wrapper and stdout
    return receive_messages


async def run_server(loop):
    """Initialize stdin and stdout asynchronous streams and start the server"""
    stdin, stdout = await aioconsole.get_standard_streams()
    stream_wrapper = StreamWrapper()
    # Asynchronously execute send_messages and start_server()
    await asyncio.gather(
        send_messages(stream_wrapper, stdin),
        asyncio.start_server(receive_messages_wrapper(stream_wrapper, stdout), '127.0.0.1', 8888, loop=loop)
    )

# Run the server on the event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(run_server(loop))
loop.close()

client.py

import asyncio
import aioconsole

async def send_messages(writer, stdin):
    # Asynchronusly read from standard input
    async for message in stdin:
        if message.decode().strip() == "q":
            writer.close()
            exit()
        else:
            # Send message through the socket
            writer.write(message)

async def receive_messages(reader, stdout):
    # Asynchronusly read messages from the socket
    async for message in reader:
        stdout.write('\nServer: {}'.format(message.decode()))
        stdout.write("Client: ")

async def run_client(loop):
    """Initialize stdin and stdout asynchronous streams and open the client connection, then start exchanging messages"""
    stdin, stdout = await aioconsole.get_standard_streams()
    reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
    stdout.write("Client: ")
    # Asynchronously execute send_messages and receive_messages()
    await asyncio.gather(
        send_messages(writer, stdin),
        receive_messages(reader, stdout)
    )

# Run the client on the event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(run_client(loop))
loop.close()

#5

Ben tam anlayamadım. Bu fonksiyonları durdurmak bekletmek eş zamanlılık falan thread denen şeyle alakalı değil miydi? Yoksa ben mi yanlış hatırladım? Kullanım alanları nelerdir? Neden kullanılırlar?


#6

thread ve asenkron tamamen farklı konular.Asenkron şöyle bir aşçı ve mutfaktaki malzemeleri düşün burada aşçı cpu ve mutfakda yiyecek malzemelerini de yapılacak işler olduğunu düşün.Bir aşçı yemek yaparken örneğin menemen yapcak, ama mutfakta domates, biber yok ama yumurta, kıyma, soğan, sucuk, salça var.Aşçı olmayan domates, biberi önemsemez onlar gelene kadar kıymayı tavaya koyar, soğanı koyar, yumurtayı koyar, domates, biber çırak tarafından getirildiğinde onları da koyar.

Ama thread da senkron işlem için bir çok aşçı vardır bunlar farklı yemekler yapıyordur ve yemek yaperken de sıralı yapmalıdır, örneğin önce tavaya yağ konmalı, sonra kıyma kızartılmalı, kıyma kızarana kadar başka hiçbir malzeme tavaya konmaz, kıyma kızarır sonra domates, biber kızartılır, sonra soğan, ve yumurta sıraysıyla kızartılıp menemen yapılır.

Ama asenkronda tek aşçının elinin altında hangi malzeme varsa tavaya dah deyip kızartmaya bakar, olmayan malzemeleri beklemez.

Her uygulamada kullanılabilir örneğin bir dosya upload ederken tarayıcı donup kalsa ve bu uploadın bitmesini beklese çok can sıkıcı olurdu, ama biz upload ederken aynı zamanda download ve sayfa gezintileri yapabiliyoruz bunlar hep asenkronun güzellikleri :smiley:

Dilim döndüğünce aradaki farkın mantıksal açıklamasını yapmaya çalıştım.


#7

async/await thread’lerle birlikte çalışıyor zaten. Bunlar dile yeni gelen ve bize kolaylık sağlayan anahtar kelimeler.


#8
async def func():
    return "asenkron"

func()
<coroutine nesnesi>

Neden coroutine nesnesi döndürdü?

Await deyimini nasıl kullanırız?


#9
#python3.6 için
import asyncio  
import time  
from datetime import datetime

#custom_sleep fonksiyonunu async ön deyimiyle yanımladık ve artık custom_sleep fonksiyonu 
#asenkron fonksiyon oldu ve bu fonk. her zaman await ile çağırarak asenkron olarak çalıştırırız.
async def custom_sleep():  
    print('SLEEP', datetime.now())
    time.sleep(1)#senkron olarak bekleme  yapıyor.
    #await asyncio.sleep(1) yukardaki satırı bu satırla değiştirirsen farkı daha iyi anlıcan, bir girdi 
    #beklerken programı bekletmez, diğer adıma geçer.

async def factorial(name, number):  
    f = 1
    for i in range(2, number+1):
        print('Task {}: Compute factorial({})'.format(name, i))
        await custom_sleep()
        f *= i
    print('Task {}: factorial({}) is {}\n'.format(name, number, f))

start = time.time()  
#aşağıdaki loop satırı 3.7 de otomatik ama önceki sürümlerde bu tanımlamayı illaki yapmamız gerekli.
loop = asyncio.get_event_loop()
'''
görev tanımlarını oluşturuyoruz task ile yani bu verdiğim fonksiyonları hangisi hazırsa onu çalıştırcak bir sıralaması yok.
'''
tasks = [  
    asyncio.ensure_future(factorial("A", 3)),
    asyncio.ensure_future(factorial("B", 4)),
]
loop.run_until_complete(asyncio.wait(tasks))  #bütün görevler bitene dek görev(task)ları tamamla.
loop.close()#asenkron çalışma düzenini sonlandırıyoruz.
'''
aşağıdaki satırlar asenkron ile senkron programlamanın ne kadar hız farkı olduğunu görebilmen için.
bunu custom_sleep fonksiyonunda time fonsiyonu yerine await asyncio.sleep(1) yazarak hız farkını görebilirsin yani asenkron daha önce çalışmayı tamamlar.
'''
end = time.time()  
print("Total time: {}".format(end - start))

Ben biraz anlatmada zorluk çekmiş olabilirim ama @ismailarilik hoca veya @dilde_olupbiten hoca daha anlaşılır anlatabilir ancak yine de bu konuyu olabildiğince anlamadığın yerleri anlatmaya çalışırım.