169 похожих чатов

Коллеги, привет! Помогите с корутинами, пожалуйста. Есть некий сервис А

с долгим процессом инициализации. И есть другой, Б, с кучей функций, который этот сервис под собой использует.

Каждая функция сервиса Б проверяет, готов ли А, и затем исполняется. Если не готов - запускает инициализацию и ждёт.

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

Инициализация сервиса А - не suspend функция, но есть коллбэк об успешном завершении. Кажется, что Channel должен здесь помочь, но я не могу знать, какое количество функций ждёт инициализацию, чтобы именно столько значений туда допихать. Если только в какой-нибудь AtomicInteger переменной считать, но мне кажется, что должно быть решение поэлегантней

22 ответов

15 просмотров

Верните результат инициализации в виде Deferred. Тогда все, кто будет делать ему await, то обудет ожидать, пока не завершится. И потом сразу все, что зависит стартанет. Не надо никаких каналов. Самый простой способ заворачивания колбэка такой: fun initialize(): Deferred<T>{ val res = CompletableDeferred<T>() startInitialization( callback = { result -> res.complete(result)} return res }

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Верните результат инициализации в виде Deferred. Т...

Выглядит классно! А если коллбек - это конкретный инстанс класса, который уже объявлен и используется всегда, есть ли какое-то более элегантное решение, чем оборачивание его в новый коллбек, который будет комплитить deferred и передавать управление?

Kamo Spertsyan
Выглядит классно! А если коллбек - это конкретный ...

При создании инстанса колбэка передать ему незавершенный деферред

Kamo-Spertsyan Автор вопроса
Alexander Nozik
При создании инстанса колбэка передать ему незавер...

он уже создан, то есть по сути это поле в классе, которое один раз создаётся. В принципе, могу переделать это поле в creator и при каждом обращении создавать новый инстанс

Kamo Spertsyan
он уже создан, то есть по сути это поле в классе, ...

Не понял, а как вы на него реагировать хотите, если на эту реакцию никак подписаться нельзя?

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Не понял, а как вы на него реагировать хотите, есл...

ну вот думаю, как это лучше всего реализовать) Коллбек-обёрткой или коллбек-криэйтором. По сути +- одно и то же

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Верните результат инициализации в виде Deferred. Т...

Мой кейс немного усложнился и теперь это решение не подходит. Дело в том, что успешная инициализация может произойти в одной из всех параллельных попыток, и в этом случае все корутины должны продолжиться, а закомплитить я смогу только один deferred, который был передан конкретно коллбеку, который вызвал успешную инициализацию. Все остальные просто не дождутся ответа (или ответ будет а-ля "уже идет процесс инициализации"). Есть ли какие-то опции для такой ситуации?

Kamo Spertsyan
Мой кейс немного усложнился и теперь это решение н...

Можно сделать несколько девередов и там по-моему есть готовый метод, который из нескольких выбирает певрый успешный, а остальные отменяет

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Можно сделать несколько девередов и там по-моему е...

а мне же надо, чтобы все успехом завершились, чтобы все ожидающие корутины продолжили выполняться

Kamo Spertsyan
а мне же надо, чтобы все успехом завершились, чтоб...

Не понял. Инициализация одна на всех или у каждого своя?

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Не понял. Инициализация одна на всех или у каждого...

Попробую чуть подробнее. Есть сервис А, который нужно инициализировать. Доступа к его коду у меня нет. Метод init() принимает коллбек, который дёргается с кодом результата. Есть также мой сервис В, в котором несколько разных методов работают с инициализированным сервисом А. Все они могут параллельно обратиться к нему и потребовать инициализации, если она ещё не произошла. То есть, скажем, 3 корутины параллельно запросили инициализацию и ждут. Первая запустила, две другие получили ответ, что "инициализация уже в процессе" и всё (коллбек отработал и больше не вызовется). Я хочу, чтобы как только инициализация из первой корутины завершилась, все 3 корутины получили результат и продолжили выполнение

Kamo Spertsyan
Попробую чуть подробнее. Есть сервис А, который ну...

deferred подходит. я так понимаю это уже и советовали

Kamo Spertsyan
Попробую чуть подробнее. Есть сервис А, который ну...

еще раз. Один раз делаете метод инициализации, который возвращает кэшированный Deferred. Потом его можно раздать всем. private val result = CompletableDeferred<T>() private var initializationStarted = false public fun initialize(): Deferred<T>{ if(!initializationStarted) { initializeService(); initializationStarted = true} return result } Или какой-то вариант на тему.

Kamo-Spertsyan Автор вопроса
Anton Lakotka
deferred подходит. я так понимаю это уже и советов...

А как с ним быть? По сути deferred-ы из двух корутин, которые вызвали init() после первой, сразу оборвутся без нужного результата. Сработает только deferred у первой

Kamo-Spertsyan Автор вопроса
Alexander Nozik
еще раз. Один раз делаете метод инициализации, кот...

А, то есть кешировать deferred? Окей, спасибо, попробую такой вариант

Alexander Nozik
еще раз. Один раз делаете метод инициализации, кот...

+ только я бы initializationStarted засинхронизировал

Kamo Spertsyan
А, то есть кешировать deferred? Окей, спасибо, поп...

Да, именно так. Или просто один раз его создать автоматом. Зависит от того, хотите вы его сбрасывать или нет.

Kamo-Spertsyan Автор вопроса
Alexander Nozik
Да, именно так. Или просто один раз его создать ав...

Хочу, в теории может повторная инициализация потребоваться

Kamo-Spertsyan Автор вопроса
Kamo Spertsyan
Хочу, в теории может повторная инициализация потре...

ну тогда делаете его нуляблем и присваиваете в иницализации вместо того, чтобы булю выносить.

Kamo-Spertsyan Автор вопроса
Anton Lakotka
+ только я бы initializationStarted засинхронизиро...

Не нужно, если сам метод синхронизирован.

Похожие вопросы

Обсуждают сегодня

А как старый хаскел с новым стыковать ? потому как тут работает https://play.haskell.org/saved/C3xpMzcd, а вот тут https://stepik.org/lesson/7602/step/9?unit=1473 нет ошибка C...
Fedor
131
что насчет пагинга? на осдеве непонятно(
Vi Chapmann 🪙
26
Вопрос я правильно понимаю что в коде newtype ArrowMap k v = ArrowMap { getArrowMap :: k -> Maybe v } getArrowMap есть функция типа k -> Maybe v, если да, то не понимаю задач...
Fedor
64
Ребят, что лучше для реверса: гидра или ида?
En Vind Av Sorg
26
Делаю велосипед логгер. К сообщению хочу прикрутить некоторую информацию, типа, кем отправлено, какой уровень, и всякое такое. И тут подумалось мне, почему бы не хранить весь...
Serjone
24
Как Вы считаете нормально ли в двадцатых годах 21 века в ВУЗах Российской Федерации обучать студентов работе с TASM? Не слишком ли это "архаично"? (Если оффтоп или флейм для э...
Spiker01
52
Комрады, хотел уточнить. Проперть в OnDestroy юнита-хозяина по-прежнему доступна? И еще уточнение: finalization юнита наступает раньше или позже OnDestroy?
Ed Doc
48
Продолжая диалог про свифт в проде – сейчас возник вопрос в активном наборе бекендеров. В основном в нашей компании мы фанаты Java Spring и полностью ей довольны. Однако найм ...
Guseyn
27
Читаю сейчас [нет, уже больше не читаю!] курсовую о Булгакове, написанную, похоже, с помощью ChatGPT. Это удивительный психоделический опыт. Текст в основном написан в стиле б...
✨ Uni [🌊 В отпуске]
1
если загрузчик efi? если сама PML4 PDPT PDT PT лежит в неудобном для меня месте?
Vi Chapmann 🪙
8
Карта сайта