简体   繁体   English

kotlin 中的延迟和 Thread.sleep 有什么区别

[英]what is the difference between delay and Thread.sleep in kotlin

I'm trying to figure out or to prove "how a delay is suspending function".我试图弄清楚或证明“延迟如何暂停功能”。
So, I wrote an example here所以,我在这里写了一个例子

var time: Long? = null
    var job1 = GlobalScope.launch() {
        println("Coroutine ${Thread.currentThread().name}")
        time = measureTimeMillis {
            Thread.sleep(1000)
            println("After 1 seconds")
            Thread.sleep(1000)
            println("After 1 seconds")
            Thread.sleep(1000)
            println("After 1 seconds")
        }

    }
    println("Thread ${Thread.currentThread().name}")

    runBlocking {
        job1.join()
        println("Proccesed time is $time")
    }

the Output I got is我得到的 Output 是

Thread main
Coroutine DefaultDispatcher-worker-1
After 1 seconds
After 1 seconds
After 1 seconds
Proccesed time is 3015

Then i replaced Thread.sleep with delay and still the processed time is 3045 ms .然后我用delay替换了Thread.sleep ,处理时间仍然是3045 ms

I don't find any difference between Thread.sleep with delay .我发现Thread.sleepdelay之间没有任何区别。
How to prove that it is a Suspending Function and is different from Thread.sleep如何证明它是一个Suspending Function并且与Thread.sleep不同

The difference is that delay is a suspend function that won't block the thread, while Thread.sleep() will block the thread.不同之处在于delay是暂停 function 不会阻塞线程,而Thread.sleep()将阻塞线程。

In other words, delay means that the coroutine suspends for that amount of time, which in turn means that the underlying Thread is free to go service a different coroutine which delays and suspends, and so on for all coroutines.换句话说, delay意味着协程暂停该时间量,这反过来意味着底层Thread可以自由地为 go 服务另一个延迟和暂停的协程,等等所有协程。

With Thread.sleep on the other hand, the underlying Thread cannot jump from coroutine to coroutine -- rather each Thread is blocked until all the sleeps in the coroutine are over before it can go service the execution of another coroutine.另一方面,使用Thread.sleep ,底层线程不能从协程跳转到协程——而是每个Thread都被阻塞,直到协程中的所有睡眠都结束,然后它才能为另一个协程的执行提供服务。

To prove this to yourself with code, run a hundred of these coroutines instead of just 1. Then try it with a thousand.为了用代码向自己证明这一点,运行一百个这样的协程,而不是仅仅运行一个。然后用一千个试试。 The Thread.sleep() version will take longer and longer to execute because the default coroutine dispatcher thread pool is quickly used up. Thread.sleep()版本的执行时间会越来越长,因为默认的协程调度器线程池很快就用完了。 On the other hand, the delay version will execute in just over 3 seconds, because there are no calls blocking the coroutine threads.另一方面, delay版本将在 3 秒多一点内执行,因为没有调用阻塞协程线程。

fun main() {
  var time: Long? = null
  time = measureTimeMillis {
    var jobs = (0..1_000).map {
      GlobalScope.launch {
        delay(1_000)
        print(".")
        delay(1_000)
        print(".")
        delay(1_000)
        print(".")
/*
        Thread.sleep(1_000)
        print(".")
        Thread.sleep(1_000)
        print(".")
        Thread.sleep(1_000)
        print(".")
*/
      }
    }

    runBlocking {
      jobs.joinAll()
    }
  }
  println("")
  println("Processed time is $time")
}

When coroutine code runs as it should -- without blocking calls like Thread.sleep() -- threads are always available to service coroutines that need to execute.当协程代码按应有的方式运行时——没有像Thread.sleep()这样的阻塞调用——线程始终可用于为需要执行的协程提供服务。 If there is no suspending equivalent available to a blocking call (for example, a 3rd party library that does synchronous I/O), always encapsulate those calls within a dispatcher designed to run such blocking calls eg withContext(Dispatchers.IO) {... } , leaving the other coroutine dispatchers free to service non-blocking coroutines.如果没有可用于阻塞调用的挂起等效项(例如,执行同步 I/O 的第 3 方库),请始终将这些调用封装在旨在运行此类阻塞调用的调度程序中,例如withContext(Dispatchers.IO) {... } ,让其他协程调度程序可以自由地为非阻塞协程提供服务。

Suspending a thread means that thread will "wait" doing something else in the meantime if necessary.挂起线程意味着线程将在必要时“等待”同时做其他事情。 Blocking a thread means that thread will wait doing nothing no matter what.阻塞线程意味着线程无论如何都会等待。

You can prove that with this code:您可以使用以下代码证明这一点:

fun log(message: String) {
    println("[${Thread.currentThread().name}] : $message")
}

fun main() {
    runBlocking {
        val myThread = newSingleThreadContext("My Thread")

        launch(myThread) {
            (1..3).forEach {
                log("1st launch: $it")
                //delay(1000)
                Thread.sleep(1000)
            }
        }

        launch(myThread) {
            (1..3).forEach {
                log("2nd launch: $it")
                //delay(1000)
                Thread.sleep(1000)
            }
        }
    }
}

Output with delay : Output 有delay

[My Thread] : 1st launch: 1
[My Thread] : 2nd launch: 1
[My Thread] : 1st launch: 2
[My Thread] : 2nd launch: 2
[My Thread] : 1st launch: 3
[My Thread] : 2nd launch: 3

Output with Thread.sleep : Output 与Thread.sleep

[My Thread] : 1st launch: 1
[My Thread] : 1st launch: 2
[My Thread] : 1st launch: 3
[My Thread] : 2nd launch: 1
[My Thread] : 2nd launch: 2
[My Thread] : 2nd launch: 3

Since delay is a suspending function it can be called only from inside a coroutine or from another suspending function.由于delay是一个暂停的 function,它只能从协程内部或另一个暂停的 function 调用。

I only will try to answer in a very simple way.我只会尝试以非常简单的方式回答。

fun main() = runBlocking<Unit> {

    launch {
        Thread.sleep(3000L)
     // delay(3000L)
        println("Coroutine 1 ${Thread.currentThread().name}")
    }

    launch {
        println("Coroutine 2 ${Thread.currentThread().name}")
    }
}

Using Thread.sleep使用 Thread.sleep

  • Here I have used runBlocking to wrap the execution of the main function.这里我使用runBlocking来封装主function的执行。 Which allows me to use launch keyword directly as it runs on context of runBlocking .这允许我直接使用launch关键字,因为它在runBlocking的上下文中运行。
  • both the launch coroutine will run on the main Thread. launch协程都将在main线程上运行。 Which can be seen by printing the thread name.可以通过打印线程名称来查看。
  • When Thread.sleep(3000L) is put inside first launch.Thread.sleep(3000L)放入第一次启动时。 The output is output 是
Coroutine 1 main
Coroutine 2 main

This is because, when first coroutine is executed it will come at Thread.sleep(3000L) which in turns block the main thread.这是因为,当第一个协程执行时,它将进入 Thread.sleep(3000L) ,这反过来又阻塞了主线程。 So, main thread is blocked and it will not handle other threads for 3 seconds.因此,主线程被阻塞,它不会处理其他线程 3 秒。

Then after 3 seconds Coroutine 1 main will get printed.然后在 3 秒后Coroutine 1 main将被打印出来。 and then Coroutine 2 main will be printed然后将打印Coroutine 2 main

Using delay使用延迟

  • now replace Thread.sleep(3000L) by delay(3000L)现在用delay(3000L)替换Thread.sleep(3000L) 3000L)
  • now when first coroutine is executed it will come at delay(3000L) which suspends the main thread.现在,当第一个协程执行时,它将在延迟(3000L)时暂停主线程。
  • now main Thread will not wait for 3 seconds instead it will start executing other coroutines.现在主线程不会等待 3 秒,而是开始执行其他协程。
  • Hence, it will execute coroutine 2 and prints Coroutine 2 main first.因此,它将执行 coroutine 2 并首先打印Coroutine 2 main
  • on back end after the delay of 3 second is over by coroutine 1. Then main Thread go back to Coroutine 1 and prints Coroutine 1 main在 3 秒的延迟后后端由协程 1 结束。然后主线程 go 回到协程 1 并打印协程Coroutine 1 main
  • So, output will be所以,output 将是
Coroutine 2 main
Coroutine 1 main

Hence, we can prove that Thread.sleep will blocking the thread, whereas delay is just suspending the thread.因此,我们可以证明Thread.sleep会阻塞线程,而delay只是暂停线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM