kotlinx.coroutines.delay() ve Thread.sleep() karşılaştırması

kotlinx.coroutines.delay() ve Thread.sleep() karşılaştırması

kotlinx.coroutines.delay() bir askıya alma işlevidir. Mevcut iş parçacığını engellemez. Thread.sleep() mevcut iş parçacığını engeller. Bu, bu konudaki diğer kodun şu zamana kadar yürütülmeyeceği anlamına gelir. Thread.sleep() çıkılır.

Örnek 1 – kotlinx.coroutines.delay()

fun main(args: Array<String>) {
    runBlocking {
            run()
        }
    }
}

suspend fun run() {
    coroutineScope {
        val timeInMillis = measureTimeMillis {
            val mainJob = launch {
                //Job 0
                launch {
                    print("A->")
                    delay(1000)
                    print("B->")
                }
                //Job 1
                launch {
                    print("C->")
                    delay(2000)
                    print("D->")
                }
                //Job 2
                launch {
                    print("E->")
                    delay(500)
                    print("F->")
                }

                //Main job
                print("G->")
                delay(1500)
                print("H->")
            }

            mainJob.join()
        }

        val timeInSeconds =
            String.format("%.1f", timeInMillis/1000f)
        print("${timeInSeconds}s")
   }
}

Asıl iş önce çalışacak ve sonra tarafından askıya alınacak delay() askıya alma işlevi, ardından İş 0 -> İş 1 -> İş 2. Tüm işler askıya alınır ve aynı anda başlatılır. Daha sonra en kısa delay() önce çalıştırılacaktır. bu timeinSeconds tüm işleri tamamlamak için en uzun olmalıdır delay() yani 2 saniye.

Çıktı şöyle görünür:

G->A->C->E->F->B->H->D->2.0s

Bunu anlamak oldukça kolaydır. ya değiştirirsek delay(2000) ile birlikte Thread.Sleep(2000) için iş1?

Örnek 2 – Dispatchers.Main üzerinde Thread.sleep()

suspend fun run() {
    coroutineScope {
        val timeInMillis = measureTimeMillis {
            val mainJob = launch {
                //Job 0
                launch {
                    print("A->")
                    delay(1000)
                    print("B->")
                }
                //Job 1
                launch {
                    print("C->")
                    Thread.sleep(2000)
                    print("D->")
                }
                //Job 2
                launch {
                    print("E->")
                    delay(500)
                    print("F->")
                }

                //Main job
                print("G->")
                delay(1500)
                print("H->")
            }

            mainJob.join()
        }

        val timeInSeconds =
            String.format("%.1f", timeInMillis/1000f)
        print("${timeInSeconds}s")
   }
}

Yukarıdaki örnek 1’e benzer şekilde, Asıl iş önce çalışacak ve tarafından askıya alınacak delay() askıya alma işlevi, ardından İş 0 İş 1. iş 0 askıya alınacaktır. Ancak, ne zaman Thread.sleep(2000) çalıştırılıyor 1. işiş parçacığı 2 saniye süreyle bloke edilecektir. 2. iş bu sırada yürütülmez.

2 saniye sonra, D önce yazdırılacak, ardından E içinde 2. iş. 2. iş sonra askıya alınır. Çünkü Asıl iş ve iş 0 2 saniyeden daha az askıya alınırsa, hemen çalışır. iş 0 askıya alma süresi daha kısa olduğu için önce çalışacaktır.

0,5 saniye sonra, 2. iş yeniden başlatılır ve tamamlanır. yazdıracak F.

Zaman damgası #1 (0 saniyeden sonra)

  • Asıl iş ve iş 0 başlatılır ve durdurulur.
  • 1. iş başlatılır ve iş parçacığını engeller

Zaman Damgası #2 (2 saniye sonra)

  • 1. iş yapıldı
  • 2. iş başlatılır ve durdurulur.
  • iş 0 ve Asıl iş yeniden başlatılır ve yapılır.

Zaman damgası #3 (0,5 saniyeden sonra)

  • iş 3 yeniden başlatıldı ve bitti

Yani harcanan toplam süre yaklaşık 2,5 saniyedir.

Çıktı şöyle görünür:

G->A->C->D->E->B->H->F->2.5s

Örnek 3 – Dispatchers.Default/IO üzerinde Thread.sleep()

Bekle, ya çalıştırırsan run kullanarak arka plan iş parçacığında işlevi askıya al Dispatchers.Default veya Dispatchers.IO. Örneğin:

runBlocking {
    withContext(Dispatchers.Default) {
        run()
    }
}

Çıktı şöyle olur:

A->C->G->E->F->B->H->D->2.0s

Çıktı şuna benzer örnek 1 yukarıda, nerede Thread.sleep() konuyu engellemiyor gibi görünüyor! Neden? Niye?

Ne zaman Dispatchers.Default veya Dispatchers.IO kullanıldığında, bir iş parçacığı havuzu tarafından desteklenir. her aradığımızda launch{}farklı bir çalışan iş parçacığı oluşturulur / kullanılır.

Örneğin, kullanılan çalışan iş parçacıkları şunlardır:

  • Ana iş – DefaultDispatcher-worker-1
  • İş 0 – VarsayılanGönderici-işçi-2
  • İş 1 – VarsayılanGönderici-işçi-3
  • 2. İş – VarsayılanGönderici-işçi-4

Şu anda hangi iş parçacığının çalıştığını görmek için println("Run ${Thread.currentThread().name}")

Yani Thread.sleep() gerçekten o iş parçacığını engeller, ancak yalnızca DefaultDispatcher-worker-3. Diğer işler, farklı iş parçacıklarında oldukları için çalışmaya devam edebilir.

Zaman damgası #1 (0 saniyeden sonra)

  • Asıl iş, iş 0, 1. iş ve 2. iş başlatılır. Sıra rastgele olabilir. Aşağıdaki Not (1)’e bakın.
  • Asıl iş, iş 0 ve iş2 askıya alınır.
  • 1. iş kendi iş parçacığını engeller.

Zaman Damgası #2 (0,5 saniyeden sonra)

  • 2. iş yeniden başlatılır ve yapılır.

Zaman damgası #3 (1 saniye sonra)

  • iş 0 yeniden başlatıldı ve bitti

Zaman damgası #4 (1,5 saniyeden sonra)

  • Asıl iş yeniden başlatıldı ve bitti

Zaman damgası #5 (2 saniye sonra)

  • 1. iş yeniden başlatıldı ve bitti

Her iş farklı bir iş parçacığında çalıştığından, iş farklı zamanda başlatılabilir. Yani A, C, E, G’nin çıktısı rastgele olabilir. Böylece, işe başlama sırasının yukarıdaki Örnek 1’dekinden farklı olduğunu görüyorsunuz.

Thread.Sleep() ne zaman kullanılır?

Thread.Sleep() neredeyse işe yaramaz çünkü çoğu zaman iş parçacığını engellemek istemiyoruz. kotlinx.coroutines.delay() tavsiye edilir.

kişisel olarak kullanıyorum Thread.Sleep() iş parçacığını engelleyen uzun süredir devam eden görevi simüle etmek için. Uzun süredir devam eden görevi arka plan iş parçacığına koyup koymadığımı test etmekte fayda var. Ana UI iş parçacığından çalıştırırsam, UI yanıt vermez.

bunu çağırırsam simulateBlockingThreadTask() ana UI iş parçacığında, ana UI iş parçacığını engeller. Uygulama, yanıt vermeyen kullanıcı arayüzü ile çökecek.

private suspend fun simulateBlockingThreadTask() {
        Thread.sleep(2000)
 }

Ancak, iş parçacığını kullanarak arka plan iş parçacığına değiştirirsek kotlinx.coroutines.withContext()buna sesleniyorum simulateBlockingThreadTask() ana UI iş parçacığından uygulama çökmez.

private suspend fun simulateBlockingThreadTask() {
    withContext(Dispatchers.Default) {
        Thread.sleep(2000)
    }
}

verim () kullanmayı unutmayın

önceki örneğimde Eşyordam Temelleri blog yazısı, kullandım yield() kırmak için Thread.sleep() temel olarak eşyordamın iptal edilebilir olmasına izin vermek. UI dizisini çok uzun süre engellememek genellikle iyi bir uygulamadır.

Kod örneğinde, hem bloke eden hem de bloke etmeyen iş parçacığı görevlerini simüle ediyorum. Toplam çalışma süresi 400 milisaniyedir.

private suspend fun simulateLongRunningTask() {
    simulateBlockingThreadTask()
    simulateNonBlockingThreadTask()
}

private suspend fun simulateBlockingThreadTask() {
    repeat(10) {
        Thread.sleep(20)
        yield()
    }
}

private suspend fun simulateNonBlockingThreadTask() {
    delay(200)
}

Çözüm

Thread.sleep() ipliği bloke eder ve kotlinx.coroutines.delay() yapmaz.

kullanırım Thread.sleep() uzun süredir devam eden görevi arka plan iş parçacığına düzgün bir şekilde yerleştirip yerleştirmediğimi test etmek için. Bunun dışında kullanmak istediğimiz herhangi bir sebep aklıma gelmiyor. Thread.sleep().

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.