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

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

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

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

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

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

22 ответов

29 просмотров

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

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

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

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

Всем привет! Имеется функция: function IsValidChar(ch: UTF8Char): Boolean; var i: Integer; ValidChars: AnsiString; begin ValidChars := 'abcdefghijklmnopqrstuvwxyzABCDE...
Евгений
44
лучше скажите, причём тут паскаль?
Alexey Kulakov
36
Чтобы перехватить все нажимания буков на форме, надо хук ставить? Пробовал на форме ОнКейДаун, оно ловит клаву если фокус не на компоненте с вводом текста
Serjone
15
Народ! Впервые клиенту пришло письмо от РКН, у вас, дескать, есть яндекс метрика, а нигде не написано, что вы ее юзаете. Никто не сталкивался?
Sasha Beep
14
Всем привет! вывожу на общей стр дочерние ресурсыв каждом ресурсе галерея, и первая фотка должна выводиться на общей [!DocLister? &prepare=photo !]
Alekso
12
А можно вопрос? Мне сегодня сказали что у меня функция (которая просто заполняет массив значениями) не правильная void Full(double * arr, int n) { for (int i = 0; i < n; i...
† C E †
7
День добрый, подскажите пожалуйста, есть ли какой-то способ сказать ребару не компилировать определённое приложение? Всю доку их перечиатл ничего подобного не нашёл
Кирилл
14
Добрый вечер. Хочу чтобы у меня в классе поле было функцией, которая возвращает строку. Делаю так: interface ... TGetOutPath = function : String of object; ... protec...
Kirill Filippenok
12
Здравствуйте, хочу сделать HelloWorld в консоли Дельфи, но функция API ничего не выводит, что я делаю не так? program Hello; {$APPTYPE CONSOLE} uses System.SysUtils, WinAPI.Wi...
Sergey Vinogradov
20
Это может быть все-таки не флудвейт? у меня ботфазер принимает изменения и отображает даже что они изменились, на видео видно что он прислал якобы уже измененное описание, н...
OVERLINK
13
Карта сайта