Разница в том, что delay
- это функция приостановки, которая не будет блокировать поток, в то время как Thread.sleep()
заблокирует поток.
Другими словами, delay
означает, что сопрограмма приостанавливается для это количество времени, которое, в свою очередь, означает, что базовый Thread
может бесплатно go обслуживать другую сопрограмму, которая задерживает и приостанавливает и т. д. для всех сопрограмм.
с Thread.sleep
с другой стороны, основной поток не может перейти от сопрограммы к сопрограмме - каждый Thread
блокируется до тех пор, пока не закончатся все спящие в сопрограмме, прежде чем он сможет go обслуживать выполнение другой сопрограммы.
Для доказательства это для себя с кодом, запустите сотню этих сопрограмм вместо одного. Затем попробуйте это с тысячей. Версия Thread.sleep()
будет выполняться дольше и дольше, потому что пул потоков сопрограммного диспетчера по умолчанию быстро израсходован. С другой стороны, версия 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")
}
Когда код сопрограмм выполняется так, как должен - без блокировки вызовов, таких как Thread.sleep()
- потоки всегда доступны для обслуживания сопрограмм, которые необходимо выполнить. Если для блокирующего вызова нет приостановленного эквивалента (например, сторонней библиотеки, которая выполняет синхронный ввод / вывод), всегда инкапсулируйте эти вызовы в диспетчере, предназначенном для выполнения таких блокирующих вызовов, например withContext(Dispatchers.IO) { ... }
, оставляя других сопрограммных диспетчеров бесплатно для обслуживания неблокирующих сопрограмм.