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

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

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

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

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

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

22 ответов

10 просмотров

Верните результат инициализации в виде 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 засинхронизиро...

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

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

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

читать файл максимально быстро? странный вопрос))
zamtmn
53
тоесть, указав return eax, сгенерируется никому ненужная инструкция mov eax,eax ?
Aiwan \ (•◡•) / _bot
24
Приветствуем всех! Устали без проектов? Если вы программист и хотите получать стабильные заказы, компания Elif предлагает вам недельный курс по поиску проектов и их ведению. ...
Elif
1
А чего сейчас в моде вместо Error для эксепшенов? А то я тут внезапно узрел что он не рекомендуется :) У Try::Tiny какой-то совершенно ужасный синтаксис если надо конкретные э...
Denis F
19
а зачем этот вопрос для удаления из чата?
Mёdkinson Medvezhkin
63
Привет. Сразу скажу, что на C/C++/Rust я не пишу, но тем не менее возникла потребность дебага C/C++/Rust кода. Суть: есть серверное приложение, которое периодически ведёт себ...
ninekeem 🐳
4
всем привет! углубившись в плюсы и начав изучать реверсинг понял, что без асм'а никуда со своими высокоабстрактными представлениями начал изучать механизмы асма, и не совсем п...
9
Всем привет, после Си стоит учить плюсы или лучше на раст перейти?
Linus
8
или вы считаете муит дает знание?
супер_лох_3000 альфа версия
12
значить например он учился в СДУ то получается он особенный?)
Asets Serikov
11
Карта сайта