Рассмотрим этот код ниже, я пытаюсь использовать Executors.newFixedThreadPool(1).asCoroutineDispatcher() для создания диспетчера одного потока; Я хочу, чтобы код внутри launch(singleThread){...} выполнялся последовательно
ожидаемый результат должен быть таким, как показано ниже, потому что асинхронный блок № 2 сначала достигает/получает синглтред
async block #2
async block #1
single thread block #2
single thread block #1
The answer is 3
но фактический результат
async block #2
async block #1
single thread block #1
single thread block #2
The answer is 3
single-thread-block-#2 и single-thread-block-#1, кажется, работают параллельно, синглтред здесь ничем не отличается
import java.util.concurrent.Executors
import kotlinx.coroutines.*
import kotlin.system.*
val singleThread = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
fun main() = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async { // async block #1
delay(200)
println("async block #1")
launch (singleThread) {
delay(500)
println("single thread block #1")
}
2
}
val two = async { // async block #2
delay(100)
println("async block #2")
launch (singleThread) {
delay(1500)
println("single thread block #2")
}
1
}
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
Функция delay() приостанавливает выполнение сопрограммы, и поэтому диспетчер может запустить другую сопрограмму, ожидая задержки.
Помните, что delay() — это функция suspend в коде. Это реализовано через приостановку сопрограммы. Это означает, что выполнение кода приостанавливается в момент вызова delay и возобновляется только по истечении тайм-аута. Поток (например, тот, который вы используете через async(singleThread) {..}, не занят ожиданием истечения времени.
Общий сценарий выглядит так
singleThreaddelay(1500), singleThread бесплатноsingleThreaddelay(500), singleThread свободнаdelay(500) для задачи 1delay(1500) для задачи 2resume(500) планирует выполнение второй части задачи 1 в singleThreadresume(1500) планирует выполнение второй части задачи 2 в singleThreadспасибо за очень хорошее объяснение, так что в singleThread нет ничего плохого, но использование delay() неправильно для предположения о длительной задаче
Мне очень любопытно, что произойдет, если delay() заменить «настоящей функцией приостановки» — то есть запись на диск, вызов функции сетевого API? Он будет работать последовательно?
В дополнение к ответу @EugenePetrenko есть новый метод CoroutineDispatcher.limitedParallelism(numberOfParallelism), который вы можете использовать, чтобы гарантировать ограничение параллелизма - в этом диспетчере может одновременно выполняться не более 1 сопрограммы. Это будет выглядеть так:
val singleThread = Dispatchers.IO.limitedParallelism(1)
someCoroutineScope.launch (singleThread) {
...
}
Функция limitedParallelism доступна, начиная с версии 1.6.0 библиотеки kotlinx.coroutines.
Я не понимаю, почему вы используете async+launch. В любом случае,
await()в сериале должен делать то, что вы хотите.