Есть ли у Kotlin функция приостановки работы в отдельном потоке? - PullRequest
0 голосов
/ 30 ноября 2018

приостановить функции запускаются в отдельном потоке?Если нет, то в чем выигрыш в производительности?

suspend fun requestToken():Token {..}  // takes 2 sec to complete
suspend fun createPost (token:Token){..} // takes 3 sec to complete

 suspend fun postItem() {
    val token = requestToken()
    val post =createPost(token)
    processPost(post)
  }

Итак, когда мы достигаем processPost (post) и если функция приостановки не запускается в отдельном потоке, тогда мы должныдождитесь requestToken () и createPost (token) метода для завершения (то есть 2 + 3 = 5 секунд) .Согласно автору, suspend является асинхронным, но если мы не создаем никакой новой нити, то как мы достигаем асинхронного поведения?

Ответы [ 3 ]

0 голосов
/ 30 ноября 2018

Точки приостановки могут использоваться только в контексте сопрограммы, например:

fun main() {
    delay(1000)
}

Не будет работать, потому что delay является функцией приостановки, и компилятор не будет знать, как справиться с этим безсопрограмма.Когда у вас есть сопрограмма, она может использовать то, что называется диспетчером, для управления владением потоком.Приостановка означает, что поток больше не используется для выполнения этой части вашей программы, а выполняет что-то еще или работает без дела.Это работает так, что вы можете иметь несколько сопрограмм, работающих одновременно, не имея потока для каждого, этот поток затем может выполнять части каждой сопрограммы вплоть до точки приостановки.Обычно идея заключается в том, что вы можете рассматривать приостановленные функции как «генераторы», у которых есть этапы для получения результата.

suspend fun hello() {
    println("Hello")
    delay(1000) // suspend here, let someone else use the thread while we wait
    println("World")
    delay(1000) // suspend again, we can still use the thread while waiting
    println("done")
}

Каждый раз, когда это приостанавливается, он использует поток для работы с другой функцией до тех пор, пока это не приостановится и не произойдет задержка.истекает, в этот момент эта функция в конечном итоге возобновит выполнение до следующей точки приостановки или полностью завершит выполнение.

Это отличается от блокировки кода, так как не тратит поток, помещая егов wait состояние, а скорее заимствует его для другой функции.Таким образом, не нужно создавать другие потоки, чтобы иметь параллелизм, поскольку вы все равно можете работать с несколькими функциями без истинного параллелизма, вместо этого он использует параллельное выполнение частей функций.

Сопрограммы не обязательно защищают вас от блокировки, если вы позвоните Thread.sleep(1000), это все равно будет блокирующий вызов.Программист несет ответственность за использование суспендирующих эквивалентов для блокировки функций, чтобы максимизировать эффективность этой концепции.

Для получения более подробной информации, пожалуйста, прочитайте документацию , поскольку она очень подробная и полезная.

0 голосов
/ 30 ноября 2018

Фоновый одиночный поток или несколько фоновых потоков пула потоков может быть явно объявлен и затем использован, например, передав его в качестве параметра, назовем этот параметр «планировщик».Самое интересное в этом то, что изначально запускаемый из основного потока, он автоматически переключается на поток планировщика для выполнения конкретной задачи на нем, и виртуальная машина в этом месте вроде как приостанавливается или прерывается, и вещь, которая даже круче основного потока, получаетразблокирована и может выполнять что-то еще, пока задание находится в фоновом режиме.

Как только задача завершена, виртуальная машина как бы возвращается к точке, в которой она была приостановлена ​​или прервана ранее, и затем возобновляет выполнение.с этого момента, но теперь, также получая результат, возвращаемый из фонового потока планировщика, ниже приведен фрагмент кода:

private val backgroundThread = ThreadPoolExecutor(1, 1, 15L, TimeUnit.SECONDS, LinkedBlockingQueue())

GlobalScope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {
    postItem(backgroundThread))
}

suspend fun CoroutineScope.postItem(scheduler: ThreadPoolExecutor): Boolean {
    val token = requestToken(scheduler)
    val post = createPost(token, scheduler)
    return processPost(post, scheduler)
}

private suspend fun CoroutineScope.requestToken(scheduler: ThreadPoolExecutor): String {
    val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val token = networkApi.requestToken()
    }

    return def.await() ?: ""
}

private suspend fun CoroutineScope.createPost(token: String, scheduler: ThreadPoolExecutor): String {
    val def: Deferred<String?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val post = networkApi.createPost(token)
    }

    return def.await() ?: ""
}

private suspend fun CoroutineScope.processPost(post: String, scheduler: ThreadPoolExecutor): Boolean {
    val def: Deferred<Boolean?> = async(scheduler.asCoroutineDispatcher(), CoroutineStart.DEFAULT) {
        val result = networkApi.processPost(post)
    }

    return def.await() ?: false
}
0 голосов
/ 30 ноября 2018

suspend является асинхронным

suspend fun s выполняется синхронно со своим вызывающим абонентом.То, что вы на самом деле хотели сказать, это «неблокирование», и это совсем другая история.

но если мы не создаем какой-либо новый поток, то как мы достигаем асинхронного поведения?

Вы делаете молчаливое предположение, что все операции ввода-вывода должны блокироваться на каком-то уровне.Это не верно.Неблокирующий ввод / вывод работает путем отправки данных в буфер отправки и получения уведомлений, когда в буфере приема есть данные.suspend fun подключается к этому механизму, приостанавливая себя после отправки данных в буфер отправки и устанавливая обратный вызов, который возобновит его, когда данные ответа будут готовы в приемном буфере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...