Класс ExecutorCoroutineDispatcher Правильная реализация

    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 и т. д.?

«Как правильно реализовать ExecutorCoroutineDispatcher?» Использовать встроенную реализацию. Не переопределяйте if самостоятельно. Кроме того, Dispatchers.Unconfined не является ExecutorCoroutineDispatcher.

Louis Wasserman 30.06.2024 23:50

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

DeadLock 01.07.2024 13:05

ссылка здесь kt.academy/article/cc-constructing-scope

DeadLock 01.07.2024 14:44
yield() должен игнорировать возвращаемое значение isDispatchNeeded по замыслу, когда dispatch() вызывается уже после проверки и должен выполнять отправку безоговорочно. Я не уверен, почему вы его переопределяете, но помните, что вы всегда можете увидеть исходный код ExecutorCoroutineDispatcherImpl в самой библиотеке сопрограмм.
Pawel 01.07.2024 16:56

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

DeadLock 01.07.2024 17:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вопрос меня довольно сбивает с толку. Вы говорите, что хотели бы реализовать диспетчер на основе исполнителя, но тогда вы хотите не отправлять, а напрямую вызывать исполняемый объект (?). Звучит весьма противоречиво.

  1. Существует существующая реализация, и, вероятно, лучше всего ее использовать: executor.asCoroutineDispatcher().
  2. Если это для обучения или у вас есть какие-то дополнительные потребности, то с текущей реализацией в основном все в порядке, вам просто нужно вернуться true из isDispatchNeeded.
  3. Если вам действительно нужно выполнить напрямую, то документация, которую вы процитировали, отвечает на этот вопрос напрямую:

Чтобы выполнить блок на месте, необходимо вернуть false из isDispatchNeeded и в таких случаях делегировать реализацию отправки Dispatchers.Unconfined.dispatch.

override fun dispatch(context: CoroutineContext, block: Runnable) = Dispatchers.Unconfined.dispatch(context, block)

спасибо за Ваш ответ! Да, вы правы. Использование executor.asCoroutineDispatcher() — рекомендуемый способ создания диспетчера сопрограммы из исполнителя. Я обязательно воспользуюсь этим подходом. извините за задержку из-за моих экзаменов

DeadLock 16.07.2024 15:22

Другие вопросы по теме