Как выполнить многопоточную обработку данных в подобии единой транзакции

1. LosevI 06.10.22 00:28 Сейчас в теме +1 $m
Здравствуйте. Итак, простейшая формулировка, и, по всей видимости, сложнейший ответ, раз его так тяжело найти на просторах сообщества 1С. Я посмотрел все статьи на тему, что смог найти, ИТС, ну и, либо плохо искал, либо ответа нет.

Как правильно и с минимальными накладными расходами на процессоре* реализовать многопоточную (средствами фоновых заданий в клиент-серверном варианте работы) обработку данных не-объектной природы (чтение + изменение записей регистров), которая должна быть выполнена либо целиком, либо вообще никак (атомарно, в общей среди потоков "транзакции")?

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

В этой статье ни слова о транзакциях. А устанавливается ли там объектная автоматическая блокировка при записи в регистр сведений с помощью менеджера? Вообще, запись ведь не является объектом. Но устанавливается ли там автоматически транзакция - я, честно, не уверен. А если она там есть, тогда что будет в рамках фонового задания потока? Предполагаю, что ничего, при неудачной записи, транзакция просто отменяется, фоновое задание завершается с ошибкой, а остальные фоновые задания пишут в регистр как ни в чем не бывало.

Начнем с фундаментальных вещей, ибо в голове уже каша. Транзакции и управляемые блокировки, если я это правильно понимаю, работают в разрезе сеанса. Один сеанс блокирует данные исключительной блокировкой, делает свои дела, другие сеансы ждут на блокировке при попытке ответственного чтения или установки собственной исключительной блокировки. Соответственно, пользователь ИБ, под которым происходит исполнение потоков, не имеет никакого значения в рамках заданного мной вопроса. Потоки могут быть запущены из другого фонового задания, запущенного регламентным заданием. В регламентном задании может быть установлено свойство ИмяПользователя. В таком случае, насколько я понимаю, все потоки будут исполняться под этим пользователем. Хорошо, но не важно. Важно то, что устанавливать блокировки и начинать транзакцию в коде головного фонового задания, или, в общем случае, в коде, который запускает исполнение потоков не правильно и ничего не решит, так как сами потоки будут являться другими сеансами, а значит ничего не будут знать о единой транзакции "головы", а при попытке чтения/изменения данных (с установкой блокировок, конечно же, не забываем, что управляемые блокировки 1С - это мьютексы окружения сервера 1С) поток встанет на блокировку и произойдет deadlock - блокировка не будет снята до завершения всех потоков, которые никуда не "двигаются", а на ней же стоят.

Если то что я написал выше - корректно, тогда размышляем дальше. Приходится в "управляющем коде" (назовем так место, которое создает потоки), предварительно разбить данные к обработке на кучи с непересекающимися областями предстоящих блокировок. Говоря проще - в разных потоках обрабатываться должны только совершенно несвязанные области данных, и потоки не должны иметь возможности создать deadlock - читать или блокировать области данных, читаемые или блокируемые другими потоками. Представим, что это нам удается сделать (это далеко не тривиальная задача, сильно зависящая от бизнес-логики). Далее, в запущенных потоках, в каждом мы отдельно начинаем собственную транзакцию и блокируем данные. Так? И тогда, как прикажете синхронизировать фиксацию/отмену этих транзакций между потоками? Мы не можем завершить фоновое задание потока, пока не поймем, что другие потоки тоже завершили свои части логики, связанные с обработкой своих данных, не увидим, удалось ли им завершить обработку успешно (результат), и только тогда мы можем принять решение о завершении транзакции потока.

Казалось бы, теоретически существует 2 способа "оптимально" ждать синхронизации. Но применимы ли они в подобной ситуации? Мне кажется, что нет:

1) Мьютекс через управляемую блокировку.
Проблемы: Блокировки снимаются только завершением транзакции. Мы не можем завершить транзакцию. Соответственно, все что заблокировано потоком, включая некий служебный объект, остается заблокированным. Да и вообще, потоки после завершения обработки учетных данных, должны записывать куда-то результат своей работы (успех/ошибка). При этом это "куда-то" должно быть заблокировано исключительной блокировкой, по которой мы потом встанем на ожидание? Кто эту блокировку вообще должен поставить, как в обход нее писать в объект, и как потом ее снять? Вообще ничего не "клеится".
Немного подумав, пришла более "жизнеспособная" идея в голову. Допустим, имеем служебный регистр сведений. В управляющем коде создаем в нем столько записей, сколько будет потоков. В каждом потоке устанавливаем исключительную управляемую блокировку на соответствующую область с единственной соответствующей записью. Записываем в нее (изменяя) результат обработки данных (флаг отказа). В конце логики потока ждем на чтение блокировку по всему регистру целиком. Только вот незадача, а как снять блокировку с области, чтобы не было deadlock'а? А вот никак. Мы уже находимся в транзакции потока, и снять отдельно блокировку служебного регистра до завершения всей транзакции мы не можем. А завершить транзакцию мы не можем, потому что ждем результатов из служебного регистра. Тупик.

2) Мьютекс через ожидание завершения фоновых заданий.
Представим себе "идиллическую ситуацию", когда внутри потока создается вложенное фоновое задание с обработкой учетных данных, другие потоки каким-то образом знают идентификаторы этих вложенных фоновых заданий и "ждут завершения на мьютексе" перед завершением своей транзакции. Круто? А, опять упираемся в проблему того, что вложенное фоновое задание ничего не будет знать о транзакции и блокировках инициализировавшего потока, потому что это уже новый сеанс! Тупик.

P.S. Ответ "это невозможно сделать без использования бешенных бесконечных циклов, внешних компонент или это вообще невозможно сделать" справедливо не будет считаться решением, и вознаграждение выдано не будет.

P.S. Статью Вы не умеете работать с транзакциями (habr) читал, Андрею Овсянкину вообще отдельное уважение за освещение темы блокировок и транзакций в 1С.
Вознаграждение за ответ
Показать полностью
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
3. nomad_irk 76 06.10.22 09:39 Сейчас в теме
(1)Если правильно понял, Вы пытаетесь реализовать управляемые блокировки поверх платформы, т.е. реализовать менеджер блокировок.
Может поделитесь условиями задачи, приведшей к такой необходимости?
2. user1203706 13 06.10.22 09:11 Сейчас в теме
(1)
Цель какая в итоге ? Возможно, задачу надо решать с другой стороны, тогда и "многопоточность" не впёрлась.
ЗЫ: ибо
"чтение + изменение записей регистров"
можно прямой записью, к примеру, читать и апдейтить
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот