Async ve await deyimleri tam olarak ne anlama geliyor?

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.

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.

7 Beğeni

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

1 Beğeni

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()
6 Beğeni

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?

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.

9 Beğeni

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

1 Beğeni
async def func():
    return "asenkron"

func()
<coroutine nesnesi>

Neden coroutine nesnesi döndürdü?

Await deyimini nasıl kullanırız?

#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 @dildeolupbiten hoca daha anlaşılır anlatabilir ancak yine de bu konuyu olabildiğince anlamadığın yerleri anlatmaya çalışırım.

1 Beğeni
#-------------------*Coroutine ve Task*-------------------------------------------------------------------
#Konu ile ilgili örnekler Python 3.7 içindir.
'''
Python coroutine:Asenkron olarak çalışan fonksiyonlara verilen addır.async def fonksiyon_adi():
şeklinde tanımlanırlar.await fonksiyon_adi() şeklinde çağırılırlar.
'''
#Coroutine Örneği
import asyncio #asenkron için modül
import time
async def main():
	print("Merhaba")
	await asyncio.sleep(1)
	print("dünya")
	'''
	asyncio.sleep(1) bu metod asenkron olarak programı uyutur(bekletir) yani await asyncio.sleep(1)
	kodu yerine time modülü içindeki time.sleep(1) metodunu kullansaydık program bu satırda hiçbir işlev
	yapmadan bir saniye boyunca tüm programı bekletirdi yani tüm program bloke olurdu ancak 
	asyncio içindeki uyku metodunu kullanarak şunu diyoruz bu satıra gelince bir saniye bekle ama 
	ana programı bloke etme; şu aşamada bu uyku konusunun etkisi  time.sleep(1) ve asyncio.sleep(1) 
	aynı görünse de ilerleyen örneklerde farkı anlayabileceğiz.Şimdilik asenkronun programı bloklamadığını
	bilmemiz yeterli.
	await bu anahtar kelime ise şu işe yarar.Tüm coroutine fonksiyonlar (async ile tanımlanmış fonsiyon)
	diğer fonksiyonlar tarafından await anahtar kelimesi kullanılarak çağırılır.Görev tamamlanana kadar
	ana programı bloklamadan, bu await ile çağırılan fonksiyonun işlevini yerine getirmesini bekler.
	'''
asyncio.run(main())#run metodu ile de ana fonksiyon çalıştırılır.

#asenkron fonksiyonlar diğer fonksiyonlar içinde şöyle çağırılır
import asyncio
import time
async def say_after(gecikme, konu):#bu fonksiyon bir coroutine'dir ve çağırılırken await ile çağırılır
	await asyncio.sleep(gecikme)
	print(konu)
async def main():
	print(f"started at {time.strftime('%X')}")
	await say_after(1, 'hello')#await ile çağırılır, zorunlu
	await say_after(2, 'world')#await ile çağırılır, zorunlu
	print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
#hemen yukarıdaki örneğimizdeki fonksiyon asenkron olsa ve senkron bir programa göre hızlı olsa da 
#esas olan asenkron programların görev olarak çağırılmasıdır bu şekilde daha hızlı bir programımız olur.
#bunu da asyncio içindeki create_task() metodu ile yaparız.
import asyncio
import time
async def say_after(gecikme, konu):
	await asyncio.sleep(gecikme)
	print(konu)
async def main():
	task1 = asyncio.create_task(say_after(1, 'hello'))#task açarken(görev oluştururken) await kullanmayız
	task2 = asyncio.create_task(say_after(2, 'world'))#task açarken(görev oluştururken) await kullanmayız
	print(f"started at {time.strftime('%X')}")
	await task1 #oluşturduğumuz görev çağırılırken await ile çağırırız.
	await task2 #oluşturduğumuz görev çağırılırken await ile çağırırız.
	print(f"finished at {time.strftime('%X')}")
asyncio.run(main())

#create_task() yerine ensure_future() metodu da kullanılabilir aynı anlamdadır.
import asyncio
import time
async def myTask():
	time.sleep(1)
	print("Processing Task")
async def main():
	for i in range(5):
		asyncio.ensure_future(myTask())
	pending = asyncio.Task.all_tasks()#çalıştırılacak olan tüm görevlerin objesini döner.Henüz daha
	#çalışmamış ama çalışacak görevler.
	print(pending)
	running = asyncio.Task.current_task()#o anda çalışan görevin örneğini döner, None dönerse çalışan 
	#bir görev yok demektir.
	print(running)
asyncio.run(main())
'''
gather() metodu ile de pek çok coroutine'yi, asenkron fonksiyonunu bir arada görevlendirebiliriz.
eğer gather() içindeki bu coroutinelerden herhangi biri iptal olursa, gather() içindaki diğer fonksiyon_
lar bundan etkilenmez ama gather() iptal olursa tüm gonsiyonlar iptal olur.
'''
import time
import asyncio
async def factorial(name, number):
	f = 1
	for i in range(2, number + 1):
		print(f"Task {name}: Compute factorial({i})...")
		await asyncio.sleep(1)
		f *= i
		if number == 0:
			print("burada sıfıra bölme hatası var ama program sonlanmadı, görev tamamlanana kadar devam etti")
			f/0
	print(f"Task {name}: factorial({number}) = {f}")
async def main():
	# gather bizim için bir program dizisi hazırlayıp çalıştırıyor.
	await asyncio.gather(
	factorial("A", 2),
	factorial("B", 3),
	factorial("C", 4),
	factorial("D", 0),
)
asyncio.run(main())

#task() metodunun cancel() fonsiyonu ile askıda olan(yapılacak olan)görevi iptal edebiliriz.
import asyncio
import time
async def myTask():
	time.sleep(1)
	print("Processing Task")
	for task in asyncio.Task.all_tasks():
		print(task) #yapılacak olan görevi listeliyoruz
		task.cancel() #yapılacak olan görevi iptal ettik
		print(task) #iptal edilen görev listesini baıyoruz.
async def main():
	for i in range(5):
		asyncio.ensure_future(myTask())
asyncio.run(main())

#ancak cancel() metodu bazı durumlarda görevi iptal etmeyi garanti edemiyor ve görev çalışa biliyor
#bu sebeple iptal edilecek bir görev varsa bunun kesin iptali için çalışan görev içerisinde try except
#bloğunda yakalamamız gerekebilir.
#aşağıdaki kod bloğunu okurken önce main(), sonra bir görev olan cancel_me() fonksiyonunu okumanızı tavsiye ederim.
import asyncio
import time
async def cancel_me():
	print('cancel_me(): before sleep')#bir defa çalışacak işiniz varsa burada yaptırabilirsiniz.do while gibi.
	try:
		# Bir saat bekle
		await asyncio.sleep(3600)
	except asyncio.CancelledError:#cancel_me() aslında iptal bir görev ama bir saniyelin bekleme yaptırınca
		#cancel_me() çalışmaya başladı, yani cancel()iptal işe yaramadı ancak python bunun iptal olduğunu hafızasında
		#tutuyor ve biz de bundan faydalanarak burada görevin iptal olup olmadığını try except ile denetleyerek
		#burada asyncio.CancelledError ile yakalıyoruz.
		print('cancel_me(): cancel sleep')
		raise
	finally:
		print('cancel_me(): after sleep')
async def main():
	# cancel_me() görevi (task'ı) oluşturduk.
	task = asyncio.create_task(cancel_me())
	# Programı bir saniye bekletince sanki iptal olmamış gibi yoluna devam ediyor.
	await asyncio.sleep(1)
	task.cancel()#her zaman görev iptal olmuyor dediğim nokta burası!
	print(task.cancelled())#burada false çıktısı ile görevin iptal olmadığını görebiliriz.
	try:
		await task #except bloğunun çalışması gerekirken try içindeki task çalışıyor. 
	except asyncio.CancelledError:
		print("main(): cancel_me is cancelled now")
		print(task.cancelled())#burada true çıktısı ile görevin iptal olduğunu anlayabiliriz.
		print(task.result())#task'ın o andaki sonucunu döndürür, mesela burada bir traceback hatasının en alt satırında
		#CancelledError döndürür.
		#//print(task.exception())#task ın CancelledError veya InvalidStateError hatasını döndürür.
asyncio.run(main())

#task metodlarından result() aşağıda görev bittiğinin sonucunu 3 olarak döüyor.
import asyncio
import time
async def cancel_me():
	await asyncio.sleep(3)
	return 3 #bu satır olmasaydı task.result() sonucu None olurdu.
async def main():
	task = asyncio.create_task(cancel_me())
	await task
	print(task.result())#task sonucunu alıyoruz.
	#//print(task.exception())#task için bir hata olmadığından None döner.
asyncio.run(main())

#get_stack() metodu
import asyncio
import time
async def cancel_me():
	await asyncio.sleep(3)
	return 3
async def main():
	task = asyncio.create_task(cancel_me())
	print(task.get_stack())#yapılacak olan görevler için bir liste içerisinde çerçeve döner.argüman olarak limit=1
	#gibi sayılar verilebilir  ama maximum limitten farklı sayıda task varsa traceback hatası döner.
	#iptal edilen veya başarıyla tamamlanmış görevler için boş liste döner.get_stack() yerine
	#print_stack() metoduda kullanılabilirdi aynı görevi görür ama çıktısı frame değil fonksiyonun adı olurdu.
	await task
	
asyncio.run(main())

#asyncio.shield() kullanımı:herhangi bir nedenden dolayı program sonlanırsa,  bu metod fonksiyonun çalışmasını iptal etmez
#onu çalıştırır.

#asyncio. shield() metodu
import asyncio
from aiorun import run, shutdown_waits_for
#aiorun modülü kurulmalıdır!
async def corofn():
    await asyncio.sleep(5)
    print('Çalıştı!')

async def main():
    try:
        #await shutdown_waits_for(corofn())#bu satırı yorumdan kaldırıp, aşağıdaki satır yoruma alınırsa program çalıştıktan sonra Ctrl+C yapsanız bile corofn fonksiyonunun çalıştığını görebiliriz.
        await asyncio.wait_for(asyncio.shield(corofn()), timeout=1.0)#programın çalışması 1 saniyeden uzun sürerse program iptal olur ancak shield() içindeki fonksiyon bu iptalden sonra bile çalışır, çünkü shield() onu koruyor.
    except asyncio.CancelledError:
        print('Program iptal edildi!')

run(main())
#shield ile herhangi bir fonksiyonu korumaya alıyoruz, eğer program herhangi bir nedenden dolayı
#sonlanırsa bile, shield() içindeki corofn() adlı fonksiyon yine de çalışır.


#asyncio.wait_for() kulanımı
#eğer bir fonksiyona belirli bir zamana kadar çalış, eğer bu zaman içerisinde çalışmazsan, bir daha
#çalışmana gerek yok, şeklinde bir kullanımı var.
import asyncio
import time
async def eternity():
	# bir saat bekletiyoruz eternity() fonksiyonunu
	await asyncio.sleep(3600)
	print('yay!')
async def main():
	try:
		await asyncio.wait_for(eternity(), timeout=1.0)#bir saniye içerisinde çalışırsan çalış, eğer çalışmazsan, çalışmaya uğraşma son bul(sona er).
	except asyncio.TimeoutError:
		print('Bir saniye doldu çalışmadın ve TimeoutError raise oldu(ortaya çıktı)!')
asyncio.run(main())

#asyncio.wait() kullanımı
#parametre olarak task olarak yarattığımız fonksiyonlar verilmelidir, eğer task yaratmadan direk olarak
#fonksiyonu verirsek, fonksiyon çalışması tamamlandığında herhangi bir kontrol imkanımız olmaz.
#(done, pending) şeklinde tamamlanmış ve yapılacak olan görev şeklinde set tiplerini döner.
import asyncio
import time
async def foo():
	return 42

async def main():
	coro = foo()
	done, pending = await asyncio.wait({coro}) #fonksiyon direk parametre olarak verilmiş.
	if coro in done:
		# bu dallanmış blok asla çalışmaz
		print("coro çalıştı ve tamamlandı")
asyncio.run(main())
# if bloğunu kullanabilmek için, task oluşturuyoruz
import asyncio #asenkron için modül
import time
async def foo():
	return 42

async def main():
	task = asyncio.create_task(foo())
	done, pending = await asyncio.wait({task})
	if task in done:
		# Foo() task olarak yaratıldığından fonksiyonun tamamlandığını veya askıda olduğunu 
		#kontrol edebiliyoruz, bu şekilde de görev tamamlanınca bu blok çalıştırılabiliyor.
		print("coro çalıştı ve tamamlandı")
asyncio.run(main())
#wait() de timeout parametresi kullanıldığında yani verilen görev belirli bir zamana kadar çalışmasını
#bitirmezse bu timeout paremetresi sayesinde programı sonlandırabiliyoruz, ama burada wait_for gibi
#bir TimeoutError çıkışı(raise) yapmaz program bu yüzden bunun kontrolünü askıda kalan(çalışmayan)
#görev var mı diye sorgulamasını yaparız.
import asyncio #asenkron için modül
import time
async def foo():
	await asyncio.sleep(7)
	return 42

async def main():
	task = asyncio.create_task(foo())
	done, pending = await asyncio.wait({task}, timeout=5.0) #5 saniyede programı tamamla yoksa görev yapılmaz diyoruz.
	if task in done:
		# Görev tamamlanırsa burası çalışır.
		print("yapıldı")
	if task in pending:
		print("5 saniye içinde yapılmadığından program sonlandı.(cancel)")
asyncio.run(main())
#wait()'e parametre olarak verebileceğimiz return_when adlı bir parametre daha var ancak kullanımı gereksiz
#ön tanımlı olarak ALL_COMPLETED yani tüm görevler tamamlandığında veya iptal(cancel) olduğunda return oluyor.
#ek olarak return_when=FIRST_COMPLETED var bu da tüm görevlerden daha ziyade bir tane bile görev tamamlansa veya
#iptal olsa return olur, son olarak return_when=FIRST_EXCEPTION bu da herhangi bir görev hata doğurursa(raise)
#döner eğer hata doğurmadan görev sonlanırsa  ALL_COMPLETED eşdeğer bir dönüş(return) sağlar.

'''
as_completed() adlı Task metodu kullanımı:bu metod parametre olarak aldığı asenkron fonksiyonları, ileride çalışacak
bir obje olarak(Future) ve iterator biçiminde(sıralı olarak, bir sonraki fonksiyonu çalıştıracak) return eder.
timeout paremetresi ön tanımlı olarak None'dır ama istersek bu paremetreye integer bir değer(örn:5)
vererek program verilen sürede bitmezse asyncio.TimeoutError hatası doğurur(raise).
'''
import time
import asyncio
async def myWorker(number):
	#await asyncio.sleep(1)
	return number * 2

async def main(coros):
	#for fs in asyncio.as_completed(coros, timeout=1): ##bu döngü kullanılırsa program bir saniye 
	##içinde bitmezse ki myWorker fonksiyonunu da her çalışmasında 1 saniye bekleyecek 
	##asyncio.TimeoutError hatası doğurur.
	for fs in asyncio.as_completed(coros):#Her çalışacak fonksiyonu(Future) (myworker fonksiyonunun farklı parametreler şeklinde alıyor) ve
		#alıp onları tek tek çalıştırabileceğimiz bir obje(Future objesi) olarak dönüyor.
		print(await fs)

coros = [myWorker(i) for i in range(5)] #Liste üreteci sayesinde myWorker'a 0'dan 4'e kadar paremetreleri gönderiyoruz.

asyncio.run(main(coros))


#----------------*Future Objesi*---------------------------------------------------------------------------------
Düşük seviyeli api ile (loops), yüksek seviyeli api (async/await) arasında köprü işlevi görüyor.
Kullanımı şuna benziyor.Biz bir fonksiyon yazıyoruz ve bu fonksiyonun gelecekte oluşacak sonucunu, 
fonksiyonda oluşabilecek hatalar veya fonksiyon hatasız sonuclanacaksa, şu fonksiyonu çalıştır şeklinde;
fonksiyonu istediğimiz gibi manipüle edebiliyoruz.

asyncio.ensure_future(obj, *, loop=None ) metodu bizim için belirli görevleri yerine getirecek şekilde
awaitable fonksiyonu parametre olarak alıp, onu işleyebilir.Yukarıda bahsedilen create_task() metoduyla
aynı işlevi görüyor.Bu şekilde başlatılan bir görev fonksiyon işini tamamlayıncaya veya iptal edilinceye 
kadar ana program çalışmaya devam eder.

import asyncio

async def set_after(fut, delay, value):
	# *delay* kadar programı uyutuyoruz.
	await asyncio.sleep(delay)
	# *fut* adlı Future nesnesinin sonuç değerini value olarak ayarlayabiliyoruz.
	fut.set_result(value)
	#fut.result() ile sonuç değerini de alabiliyoruz ancak burada gerek yok set_result bizim için zaten sonuç değerini return ediyor

async def main():
	# mevcutta çalışan loop nesnesini alıyoruz.Future objeleri yaratmak için gerekli bir kalıptır.
	loop = asyncio.get_running_loop()
	# Yeni bir future objesi yaratıyoruz.
	fut = loop.create_future()
	#"set_after()" korotin fonksiyonunu paralel bir görev olrak çalıştırmak için bu satırı kulanıyoruz.
	#loop.createtask() yerine "asyncio.create_task()" veya "asyncio.ensure_future()" da kullanabiliriz.
	loop.create_task(set_after(fut, 1, '... world'))
	print('hello ...')
	# *fut* objesinden değer gelene dek program bekler ve sonucu basar.
	print(await fut)
asyncio.run(main())

#future ile program iptal edilmedi ise şu sonucu dön, şeklinde bir komut da oluşturabiliriz.

import asyncio

async def cancel_or_not(fut):
	#bu satrıda fut.cancel() yapılırsa CanceledError hatası oluşur.(raise)
	if not fut.cancelled():
		fut.set_result(42)

async def main():
	# mevcutta çalışan loop nesnesini alıyoruz.Future objeleri yaratmak için gerekli bir kalıptır.
	loop = asyncio.get_running_loop()
	# Yeni bir future objesi yaratıyoruz.
	fut = loop.create_future()
	loop.create_task(cancel_or_not(fut))
	# *fut* objesinden değer gelene dek program bekler ve sonucu basar.
	print(await fut)
asyncio.run(main())

#add_done_callback(callback, *, context=None ) metoduyla Future objesi oluştuğunda bir fonksiyon ile
#bunu belirtebiliriz.
import asyncio

async def cancel_or_not(fut):
	if not fut.cancelled():
		fut.set_result(42)

async def main():
	# mevcutta çalışan loop nesnesini alıyoruz.Future objeleri yaratmak için gerekli bir kalıptır.
	loop = asyncio.get_running_loop()
	# Yeni bir future objesi yaratıyoruz.
	fut = loop.create_future()
	loop.create_task(cancel_or_not(fut))
	# *fut* objesinden değer gelene dek program bekler ve sonucu basar.
	print(await fut)
	fut.add_done_callback(print("fonksiyon çalışması bitti"))#cancel_or_not çalışması bitince çalışır
	#bu komutu şöyle de yazabiliriz.fut.add_done_callback(functools.partial(print, "Bitti"))
	#loop.call_soon(print("fonksiyon çalışması bitti"))##cancel_or_not çalışması bitince çalışır, yukardaki
	#satırda yer alan fut.add_done_callback komut yerine kullanılabilir.
asyncio.run(main())










	
6 Beğeni

Teşekkürler hocam bende bilmiyordum öğrenmiş oldum :slight_smile:

Affınıza sığınıyorum, anlamadım.

Ana postta ki örnek uygulamada şöyle bir satır var;

name = await websocket.recv()

Bu, asenkron olarak kullanıcı adını beklerken işleme devam etmesini sağlıyor demişsiniz. Ama şöyle bir problem var, kodun devamında gelen veriye göre “hello name” dönüşü sağlanıyor. E biz name değerini bekliyoruz, daha gelmedi ama kod işlemeye devam etti. Ne gönderecek bu durumda?

Bu kod degil, baska bir kod islemeye devam ediyor. Ornegin name’i gelmis ikinci bir kopya var: Bu kopya name’i beklerken, digeri “hello name” donebiliyor.

1 Beğeni

Teşekkür ediyorum ^^

Asenkron programlama ile paralel programlama arasındaki farkı gösteren birbirine benzer iki farklı uygulama yapalım.

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-

import time

def fonksiyon(süre, metin):
    time.sleep(süre)
    print(metin)

print(f"Başlama Tarihi: {time.strftime('%X')}")
fonksiyon(1, "merhaba")
fonksiyon(1, "dünya")
print(f"Bitiş Tarihi: {time.strftime('%X')}")

Bu yukarıdaki kodları çalıştırırsak şöyle bir çıktı almamız gerekir:

Başlama Tarihi: 17:19:35
merhaba
dünya
Bitiş Tarihi: 17:19:37

Gördüğünüz gibi başlangıç ve bitiş tarihleri arasında 2 saniye fark var. Yani merhaba yazısı yazdırılmadan önce fonksiyon 1 saniye bekledi ve sonra merhaba yazısı yazdırıldı. Merhaba yazısı yazdırıldıktan sonra fonksiyon yine 1 saniye bekledi ve son olarak dünya yazısı ekrana yazdırıldı.

Bu işlemi asenkron programlama modeline göre yazsaydık şöyle yazmamız gerekirdi:

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import time
import asyncio

async def fonksiyon(süre, metin):
    await asyncio.sleep(süre)
    print(metin)
    
async def main():
    görev1 = asyncio.create_task(fonksiyon(1, "merhaba"))
    görev2 = asyncio.create_task(fonksiyon(1, "dünya"))
    print(f"Başlama Tarihi: {time.strftime('%X')}")
    await görev1
    await görev2
    print(f"Bitiş Tarihi: {time.strftime('%X')}")
    
asyncio.run(main())

Bu kodları çalıştırdığımız zaman ise şöyle bir çıktı almamız lazım:

Başlama Tarihi: 17:24:22
merhaba
dünya
Bitiş Tarihi: 17:24:23

Gördüğünüz gibi başlangıç ve bitiş tarihleri arasında 1 saniye fark var. Yani merhaba ve dünya yazılarını ekrana yazdıran fonksiyon aynı anda beklemeye başladı ve bekleme süreleri eşit olduğu için aynı anda da ekrana yazdırıldılar.

Bu yukarıdaki işlem asenkron programlama ile paralel programlama arasındaki en temel fark.

Bu arada python3.7’ye göre yazılmış olan kodlarla benzer bir iş yapan kodları python3.6’da oluşturmak için kodlarda şöyle bir değişiklik yapılması gerekirdi:

#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-

import time
import asyncio

async def fonksiyon(süre, metin):
    await asyncio.sleep(süre)
    print(metin)
    
async def main(loop):
    görev1 = loop.create_task(fonksiyon(1, "merhaba"))
    görev2 = loop.create_task(fonksiyon(1, "dünya"))
    print(f"Başlama Tarihi: {time.strftime('%X')}")
    await görev1
    await görev2
    print(f"Bitiş Tarihi: {time.strftime('%X')}")
        
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))

Yukarıdaki kodlar ile bir önceki kodlar arasında hiçbir fark yok. Hatta son paylaştığım kodlar, hem 3.6 hem de 3.7 sürümlerinde geçerli. python’ın 3.7 sürümünde asyncio modülünde bir takım değişiklikler yapıldı.

Örneğin:

python3.6’da olup python3.7’de kullanımdan kaldırılan özellikler:

  1. async fonksiyonu
  2. compat modülü
  3. selectors modülü

python3.7’ye eklenen yeni özellikler ise şunlardır:

  1. BufferedProtocol sınıfı
  2. SendfileNotAvailableError hata sınıfı
  3. all_tasks fonksiyonu
  4. create_task fonksiyonu
  5. current_task fonksiyonu
  6. run fonksiyonu
  7. get_running_loop fonksiyonu
  8. format_helpers modülü
  9. runners modülü
2 Beğeni

async deyimini async for şeklinde kullanabilmek için for döngüsünde bir __aiter__ kullanmak gerekir. Mesela aşağıdaki gibi:

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import time
import asyncio

now = lambda: time.strftime("%Y.%m.%d %H:%M:%S")

async def task(number):
    for i in range(1, number + 1):
        yield asyncio.sleep(1)
              
async def main():
    async for i in task(5):
        await i
                     
print("--- <Örnek-1> ---", now())
asyncio.run(main())
print("--- </Örnek-1> ---", now()) 

Yukarıdaki kod şu şekilde de yazılabilirdi:

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import time
import asyncio

now = lambda: time.strftime("%Y.%m.%d %H:%M:%S")

async def task(number):
    for i in range(1, number + 1):
        yield i

async def main():
    async for i in task(5):
        await asyncio.sleep(1)
              
print("--- <Örnek-2> ---", now())
asyncio.run(main())
print("--- </Örnek-2> ---", now())

Yukarıdaki kodlarla aynı işlemi yapan async for deyiminin kullanılmadığı bir örnek de şu olabilir:

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-

import time
import asyncio

now = lambda: time.strftime("%Y.%m.%d %H:%M:%S")

async def task(sleep):
    await asyncio.sleep(sleep)

async def main():
    tasks = [task(i + 1) for i in range(5)]
    for i in asyncio.as_completed(tasks):
        await i

print("--- <Örnek-3> ---", now())
asyncio.run(main())
print("--- </Örnek-3> ---", now())

async keywordu asyncio modülü olmadan çalışmıyorsa bir deyim modül içinde tanımlanabilir denebilir mi?

async keywordu asyncio modülü olmadan çalışmıyor evet, ama bir fonksiyonu asenkron olarak tanımlayıp, fonksiyonu çağırmazsanız, programınız hata vermez. :slight_smile:

async def f(): return

Hımm, neden böyle düşündünüz acaba?

Dogrudan bir mantik zinciri olusmasa da, cok uzaga bir atlayis degil:

X sadece M moduluyle kullanilabilen bir fonksiyonaliteyse X’i M modulu mu tanimliyor?

Fakat cevap tam tersi, @Emerald_Gamer: async sadece asyncio moduluyle kullanilabiliyor. Bu keyword’u asyncio tanimlayamadigi icin dilin kendisine eklenmis durumda. Cagrilmadigi surece hata vermemesinin sebebi bu.


Ama cevap bu degil. Coroutine’ler generator mekanizmasina baglanmis durumda. asyncio olmadan kullanilabiliyorlarmis:

async def foo():
	return 42

try:
	foo().send(None)
except StopIteration as si:
	print(si.value)
3 Beğeni

Biraz kurcalayınca şöyle birşey buldum.

async def foo():
    yield 42
    yield "A"


print(foo().ag_code.co_consts)
1 Beğeni