Kotlin Coroutines Nedir? Neden Kullanılır?
Selamlar 👋🏻
Bu yazıda, Kotlin diline 1.3 versiyonuyla eklenen Kotlin Coroutines nedir, ne işe yarar, neden kullanılır gibi sorulara cevap bulacağız. Gelişmiş yapılara dalmayıp genel bir bakış sağlıyor olacağız.
Kelime anlamı eşgüdüm — ortak rutin olan Coroutine için kotlin ekibinin tanımı lightweight threads şeklinde, fakat Thread Tarafından Yürütülen Görev Parçaları olarak tanımlamak daha sağlıklı olacaktır.
Nedir ? Neden Kullanılır ?
Coroutines, uzun süren işlemlerde Main Thread’i bloklamamak için kullanılır. Ana thread bloklandığı zaman uygulama ANR (Application Not Responding) hatası alır.
Threadleri blocklamadan Asenkron programlama yapma imkanı sunan Kotlin Coroutines, bizlere temel olarak asenkron işlemleri çok daha basit ve daha iyi şekilde gerçekleştirme imkanı sağlıyor.
Coroutineler threadlerin engellenmesini önlemek ve threadleri yeniden yapılandırmak için daha ucuz, daha kontrol edilebilir bir yapı sağlarlar.
Coroutineler main threadde çalışır fakat main threadi bloke etmez.
Kadim zamanlarda işlemleri Thread veya AsyncTasks ile yapiyorduk. 😅 Sonra Callback’ ler, RxJava, EventBus gibi library’ler ile gerçekleştirmeye başladık. Fakat artık, bu yöntemler ve libraryler yerine Kotlin Coroutines kullanmanın daha çok iyi bir çözüm olduğu savunuluyor.
2018 KotlinConf (providing deep-dive technical content on Kotlin) koferansında da Coroutine’lerin artık deneysel olmadığı, güvenli bir şekilde kullanabileceğimiz dile getirildi.
Suspend Functions :
Hafif yüklü, suspend fonksiyonlar (askıya alınmış) , geçerli iş parçacığını engellemeden geçerli Coroutin’in yürütülmesini askıya askıya alır. Böylece thread başka bir Corutinenin işletilmesine başlar. Cpu daha verimli bir şekilde kullanılmış olur.
Suspend fonksiyonlar sıralı işletilirler. Yani bir dönüş değeri almadan veya kodun geri kalanını çalıştırmadan önce, çağrılan suspend fonksiyonun yürütülmesini beklemek gerekir.
suspend
fonksiyonlar normal fonksiyonlar gibi parametre alabilir veya bir return değeri olabilir. Fakat sadece Coroutine’ler veya diğer suspend
fonksiyonlar tarafından çağrılabilir.
Bir iş parçacığı(thread), bazı belirli askıya alma noktalarında(suspension points) bir coroutin yürütmeyi durdurabilir ve gidip başka bir iş yapabilir. Suspend olan görev daha sonra, durdurulan coroutini yürütmeye devam edebilir veya başka bir iş parçacığı(thread) devralabilir. Bu sayede thread’ler verimli şekilde bloklanmadan kullanılmış olur.
Bu sebeple Coroutin tam olarak bir görev(task) değil de, belirli ve garantili bir sırada yürütülecek alt görevler (sub-tasks) dizisi olarak ifade edilebilir.
Tüm bu süreci CoroutineDispatcher organize eder.
Suspension point denilen bloklayıcı bir bölüme gelindiğinde, thread coroutine’i bırakarak ve başka bir coroutine’i çalıştırmaya başlayabilir.(context switch).
Coroutine Dispatcher :
Coroutin’i yürütmek için hangi thread veya threadlerin kullanıldığını belirleyen görevler arasındaki senkronizasyon sağlayan Coroutine Dispatcher bir Thread Pool gibi çalışır.
Farklı bir tabirle; Coroutine’i spesifik bir threadde çalıştırabileceğimiz Coroutine-Tread Planlayıcısı olarak düşünebiliriz.
launch
veya async
içerisinde UI threadi ile alakalı bir güncelleme yapılacağı zaman bunu Android sistemine haber veren yapı Dispatchers.Main
dir.
Klasik thread bloklama : runBlocking
Normal bir fonksiyon ile suspending işlem yapmanın en basit yolu; yalnızca geçerli iş parçacığını bloke etmek ve beklemektir (Thread.sleep() gibi ). Geçerli thread’i engellemek için runBlocking olarak adlandırılan coroutine oluşturucu kullanılabilir.
Launch ve Async 😍
Coroutine’lerin amacı thread’leri engellemek değil, eşzamansız bir görev (asynchronous task) başlatmaktır.
launch
ve async
olarak adlandırılan coroutine oluşturucuları ile arka planda yeni bir coroutine başlatmaya ve bu arada çalışmaya devam etmeye izin verir.
launch : “Fire and Forget” diye tabir edilir. Geçerli threadi bloklamadan yeni bir coroutine başlatır ve herhangi birşey döndürmez. Arka planda yapılacak işlemler (Job) için kullanılan builder tipidir.
Job
iptal edilene kadar coroutine işini yapmaya devam eder diğer işlemler bu süreci beklemez. Ayrıca geçerli threadi durdurmak için runBlocking
yapılandırıcısı kullanılabilir.
async : Yeni bir coroutine başlatır ve suspend fonksiyon olan await ile birlikte coroutine’e Deferred türünde bir geri dönüş değeri sağlar.
Normal işleyişi bloklayan ve süreci bitirip sonucu dönene dek bizi bekleten bir çağrıdır.
Coroutine tarafından işlem sonucu dönecek bir değere ihtiyaç varsa await kullanımı tercih edilir.
Deferred
iptal edilene veta bitene kadar coroutine işini yapmaya devam eder. Diğer işlemler bu süreci bekler.
CoroutineScope :
CoroutineScope, tüm alt koroutinlerin yürütülmesini bitirene kadar geçerli Coroutinei askıya alır.
Bir coroutine başlatmak ve onu çalıştırmak için CoroutineScope gibi bir Context sağlamamız veya GlobalScope kullanmanız gerekir.
CoroutineScope bir RXJava zamanlayıcı gibi çalışır, ancak aşağıdaki parametreler ile tanımlanan başka birçok özelliğe sahiptir :
Coroutines oluşturan bir işlev yazarken, bunu CoroutineScope sınıfının bir uzantısı olarak bildirmelisiniz.
Bir Coroutine(eşgüdüm) oluşturmak için, ya bu derleyicileri GlobalScope’ta (üst düzey bir coroutine oluşturarak) ya da halihazırda var olan bir coroutine kapsamından (bu kapsamın bir alt yordamını oluşturarak) çağırmak gerekir.
Bir Suspending fonksiyon asynchronously olarak tek bir değer döndürür,
Birden çok değeri dönderme işlemini synchronously olarak yapmak için de Sequences kullanılabilir,
Asynchronously olarak hesaplanmış birden çok değeri döndürme noktasında Kotlin Flows devreye giriyor. Detaylar için guide’ı inceleyebilirsiniz.
Channels :
Deferred values (ertelenen değerler), Coroutineler arasında tek bir değeri aktarmanın uygun bir yolunu sağlarken,
Channels, stream değer akışını aktarmanın bir yolunu sağlar.
Coroutine kullanımı için BestPractice ; View Model içerisinde coroutine çağrısı yapmak. ViewModel onCleared olduğunda da job cancel etmek.
Veya bu işi manuel değil de otomatize yaptırmak istiyorsak, viewModelScope tüm cancel-clear süreçlerini bizm için halledecektir. 😎
Şimdilik bu kadar, bir sonraki yazıda görüşmek üzere 👋🏻