Здравствуйте, zelenprog, Вы писали: Z>Но мы ведь должны перейти уже к конкретному решению.
Z>Какой механизм (архитектуру) вы имели ввиду? В каком слое будет формироваться этот прогресс? В бизнес-логике? Z>В каком виде это прогресс передаваться в UI?
Как конкретно реализовать — вариантов масса.
Приведу для примера как у меня в одном из проектов сделан механизм обработки на клиенте изменений в базе на сервере (которые делают другие пользователи).
По сути от прогресса мало чем отличается. Только тут "операция" длительностью во все время жизни клиентской сессии.
При подключении к серверу клиент регистрирует себя как подписчика на изменения, получает некий id.
Под этот id на сервере создается "указатель" на общий список изменений. У каждого подписчика "указатель" свой и они могут указывать в разные места списка.
Элементы в конец общего списка изменений добавляет бизнес-логика сервера в контексте каждой клиентской сессии (документ id такой-то изменил пользователь Вася, например).
Клиент по id подписчика спрашивает сервер о новых изменениях, получает их список (от тек. положения указателя до конца списка).
При этом указатель этого подписчика на сервере перемещается в конец списка.
Все элементы списка, которые расположены до (раньше) всех имеющихся "указателей" более никому не нужны и сервер их удаляет.
Могут быть ленивые подписчики, которые не опрашивают регулярно изменения. Из-за них размер общего списка изменений может расти с хвоста и не уменьшаться с головы.
Поэтому есть некий предел количества событий, которые может содержать общий список.
При его превышении список принудительно сокращается с головы, а все указатели, находящиеся в диапазоне от старой головы до новой, переводятся в специальное состояние "overflow".
Т.е. когда клиент опрашивает сервер на предмет новых изменений, то он может получить:
1) пустой список — нет изменений, ничего обновлять не надо;
2) список из 1 или более изменений — смотрим на характер изменений и обновляем, что требуется;
3) признак "overflow" — было слишком много изменений, которые мы проспали, обновляем все.
Сам опрос изменений может быть по таймеру, по явному нажатию кнопки пользователем, по каким-то иным событиям в клиентской программе.
Если вернуться к задаче с прогрессом, то тут еще проще.
При запуске длительной операции получаем ее task id.
На стороне бизнес-логики можем привязать по task id какую-то структуру данных, например список сделанного.
Передаем этот список по мутабельной ссылке в функцию длительной операции.
Эта функция добавляет элементы в этот список по ходу своей работы.
Клиент может по task id запросить список новых элементов, при этом список на стороне бизнес-логики очищается.
По сути, получается как в предыдущем примере, только подписчик строго один и поэтому не нужен общий список и "указатели".
Если вернуться к ограничению, что все должно быть в один поток, то тут только передача callback в длительную функцию бизнес-логики.
В неких контрольных точках длительной функции надо вызывать callback и передавать туда текущий список, а потом его очищать.
Или просто дергать callback на каждый обработанный элемент и обойтись вообще без списков (это если обработка элементов не как из пулемета).
Но в таком сценарии будут проблемы с обновлением UI из стека длительной функции бизнес-логики:
1) не все элементы UI обновляются синхронно, иногда надо прокачивать сообщения, чтобы все корректно отрисовалось;
2) контрольные точки (вызов callback) должны быть достаточно частыми, иначе система сочтет, что программа "Не отвечает".