class dispatch : ExecutorCoroutineDispatcher() {
private val services = Executors.newCachedThreadPool()
override val executor: Executor
get() = services
override fun dispatch(context: CoroutineContext, block: Runnable) {
println("dispatch ")
if (this.isDispatchNeeded(context)){
executor.execute(block)
}else{
Dispatchers.Unconfined.dispatch(context , block)
}
}
override fun isDispatchNeeded(context: CoroutineContext): Boolean {
println("isDispatchedNeeded ")
// Implement your custom logic here to determine if dispatch is needed
return false // assuming yield() call in loop so return false
}
override fun close() {
services.shutdown()
}
}
fun main() {
runBlocking {
launch(dispatch()) {
for (i in 1..3) {
println("start")
yield()// dispatch() call in loop may cause stackOverFlowError
println("end")
}
}
launch(dispatch()) {
println("some suspend function")
work() // some suspend work
}
}
}
suspend fun work() {
delay(1000) // Simulating some suspend work
}
Я прочитал это диспетчер(). я не мог понять, как лучше реализовать эту функцию в соответствии с документацией по диспетчеризации (). как они говорят о
Этот метод должен гарантировать, что данный блок в конечном итоге будет вызван, иначе система может зайти в состояние тупика и никогда из него не выйти.
Этот метод не должен сразу вызывать блок . Это может привести к возникновению StackOverflowError при многократном вызове диспетчеризации, например, когда выход вызывается в цикле. Чтобы выполнить блок на месте, необходимо вернуть false из isDispatchNeeded и в таких случаях делегировать реализацию диспетчеризации Dispatchers.Unconfined.dispatch. Для этого механизм сопрограмм обеспечивает выполнение на месте и формирует цикл событий, чтобы избежать несвязанной рекурсии.
---> в моем коде, когда в цикле есть метод yield(), то isDispatchNeeded возвращает false, а при отправке используйте Unconfined Dispatcher, как указано выше в документации, чтобы избежать ошибки stackoverflow, но в документации, как я могу справиться, когда нам нужно немедленно вызвать блок [runnable] чтобы избежать тупика.
пожалуйста, кто-нибудь Исправьте мой код, который правильно обрабатывает отправку сопрограмм, учитывая, вызывается ли диспетчер() в цикле или нет, и должен ли он обеспечить правильную обработку ошибок и управление исключениями в диспетчеризации(), isDispatchedNeeded(), которые обрабатывают такие проблемы, как взаимоблокировка или StackOverflowError и т. д.?
на самом деле я читал, что причиной реализации этого класса является диспетчер, созданный из Executors, который является хорошим выбором, если вы хотите настроить свои потоки способами, которые невозможны с помощью диспетчеров Kotlin Coroutines (например, установка приоритетов, имен, типов и т. д.). .
ссылка здесь kt.academy/article/cc-constructing-scope
isDispatchNeeded
по замыслу, когда dispatch()
вызывается уже после проверки и должен выполнять отправку безоговорочно. Я не уверен, почему вы его переопределяете, но помните, что вы всегда можете увидеть исходный код ExecutorCoroutineDispatcherImpl в самой библиотеке сопрограмм.
Да, ты прав. Я прочитал об этом больше и теперь понимаю, что правильный способ реализации ExecutorCoroutineDispatcher — использовать встроенную реализацию, а не переопределять ее самостоятельно, если только у вас нет конкретного варианта использования, требующего специальной конфигурации, например установки приоритетов или имен потоков. . Я думаю, что переопределение важно, поэтому я задал вопрос, чтобы узнать, есть ли у кого-нибудь больше понимания, но я ценю отзывы
Вопрос меня довольно сбивает с толку. Вы говорите, что хотели бы реализовать диспетчер на основе исполнителя, но тогда вы хотите не отправлять, а напрямую вызывать исполняемый объект (?). Звучит весьма противоречиво.
executor.asCoroutineDispatcher()
.true
из isDispatchNeeded
.Чтобы выполнить блок на месте, необходимо вернуть false из isDispatchNeeded и в таких случаях делегировать реализацию отправки Dispatchers.Unconfined.dispatch.
override fun dispatch(context: CoroutineContext, block: Runnable) = Dispatchers.Unconfined.dispatch(context, block)
спасибо за Ваш ответ! Да, вы правы. Использование executor.asCoroutineDispatcher() — рекомендуемый способ создания диспетчера сопрограммы из исполнителя. Я обязательно воспользуюсь этим подходом. извините за задержку из-за моих экзаменов
«Как правильно реализовать ExecutorCoroutineDispatcher?» Использовать встроенную реализацию. Не переопределяйте if самостоятельно. Кроме того,
Dispatchers.Unconfined
не являетсяExecutorCoroutineDispatcher
.