![]() |
![]() |
![]() |
|
Блокировки в СУБД | ☑ | ||
---|---|---|---|---|
0
unit_3q
14.04.15
✎
08:49
|
Доброго дня, люди.
Пишу внешнюю обработку по изменению элементов справочника "Номенклатура", надо выставить всем элементам реквизит "ВестиУчетПоСериям" в "Ложь". Платформа 8.3.5.1119, конфигурация УПП 1.3.12.1, режим клиент-серверный, оборудование.. эээ.. хорошее. Написал, работает. Но долго, т.к. элементов многовато. Подумал про многопоточность, посмотрел в сторону фоновых заданий. Переделал обработку, благо руки-время есть и информации в сети достаточно. Например, тут, у Гилева - http://xn----1-bedvffifm4g.xn--p1ai/articles/как-ускорить-1с-многопоточность/ . Ок. Делаю 10 процессов, запускаю. Но из 10 процессов нормально отрабатывает свою порцию данных только 1, остальные 9 завершаются аварийно, с ошибкой "Ошибка при вызове метода контекста (Записать): Ошибка при выполнении обработчика - 'ПриЗаписи': {ОбщийМодуль.МодульСИ.Модуль(210)}: Ошибка при вызове метода контекста (Выполнить): Ошибка выполнения запроса: Конфликт блокировок при выполнении транзакции: Microsoft SQL Server Native Client 10.0: Транзакция (идентификатор процесса 68) вызвала взаимоблокировку ресурсов блокировка | буфер связи с другим процессом и стала жертвой взаимоблокировки. Запустите транзакцию повторно. HRESULT=80004005, SQLSrvr: SQLSTATE=40001, state=34, Severity=D, native=1205, line=1" Предполагаю, что происходит эскалация блокировок. Изменил режим управления блокировками конфигурации с автоматического на управляемый. Не помогло. Может есть у кого еще предположения по устранению причины ошибки? Код общего неглобального модуля, который выполняет обработку данных: [code] // тзНоменклатура - таблица значений: // 1. Ссылка, ссылка на элемент справочника Номенклатура // Процедура УстановитьЗначениеНастройки(тзНоменклатура, ИндексНачала, РазмерПорции) Экспорт Для й = 1 По РазмерПорции Цикл НоменклатураОбъект = тзНоменклатура[ИндексНачала + й].Ссылка.ПолучитьОбъект(); НоменклатураОбъект.ВестиУчетПоСериям = Ложь; НоменклатураОбъект.ВестиУчетПоСериямВНЗП = Ложь; НоменклатураОбъект.ВестиПартионныйУчетПоСериям = Ложь; НоменклатураОбъект.ОбменДанными.Загрузка = Истина; Попытка НоменклатураОбъект.Записать(); Исключение ВызватьИсключение ОписаниеОшибки(); КонецПопытки; КонецЦикла; КонецПроцедуры [/code] Код обработки, которая создает фоновые задания: [code] Перем КоличествоПотоков; Перем СоответствиеЗаданий; Процедура КнопкаВыполнитьНажатие(Кнопка) Сообщить("Запуск: " + Строка(ТекущаяДата())); // 2. сбрасываем настройку в справочнике "Номенклатура" Состояние("Сбрасываем настройку в справочнике ""Номенклатура"".."); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Номенклатура.Ссылка |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | (Номенклатура.ВестиУчетПоСериям = ИСТИНА | ИЛИ Номенклатура.ВестиУчетПоСериямВНЗП = ИСТИНА | ИЛИ Номенклатура.ВестиПартионныйУчетПоСериям = ИСТИНА)"; тзНоменклатура = Запрос.Выполнить().Выгрузить(); КоличествоНоменклатуры = тзНоменклатура.Количество(); Сообщить("Элементов номенклатуры к обработке - " + Строка(КоличествоНоменклатуры) + ", " + Строка(ТекущаяДата())); РазмерПорции = Цел(КоличествоНоменклатуры / КоличествоПотоков); МассивЗаданий = Новый Массив; СоответствиеЗаданий = Новый Соответствие; Для НомерПотока = 1 По КоличествоПотоков Цикл // с какого индекса взять ИндексНачала = (НомерПотока - 1) * РазмерПорции; // сколько взять Если (НомерПотока = КоличествоПотоков) Тогда РазмерПорции = КоличествоНоменклатуры - (КоличествоПотоков * РазмерПорции) + РазмерПорции; КонецЕсли; // берем в обработку Параметры = Новый Массив; Параметры.Добавить(тзНоменклатура); Параметры.Добавить(ИндексНачала); Параметры.Добавить(РазмерПорции); Ключ = Новый УникальныйИдентификатор; Сообщить(" Старт потока № " + Строка(НомерПотока) + ", " + Строка(ТекущаяДата()) + ". Обработка записей с " + Строка(ИндексНачала) + ", размер порции " + Строка(РазмерПорции)); Задание = ФоновыеЗадания.Выполнить("ОчисткаНоменклатуры.УстановитьЗначениеНастройки", Параметры, Ключ, "Поток Номер " + Строка(НомерПотока)); МассивЗаданий.Добавить(Задание); СоответствиеЗаданий.Вставить(НомерПотока, Ключ); КонецЦикла; ПодключитьОбработчикОжидания("ВывестиРезультат", 5); КонецПроцедуры Процедура ВывестиРезультат() Для каждого элемент Из СоответствиеЗаданий Цикл // 1. Отбор = Новый Структура; Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Завершено); Отбор.Вставить("Ключ", элемент.Значение); МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); Если МассивЗаданий.Количество() > 0 Тогда Сообщить(" Поток № " + элемент.Ключ + " завершен успешно!"); СоответствиеЗаданий.Удалить(элемент.Ключ); КонецЕсли; // 2. Отбор = Новый Структура; Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.ЗавершеноАварийно); Отбор.Вставить("Ключ", элемент.Значение); МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор); Если МассивЗаданий.Количество() > 0 Тогда Сообщить(" Поток № " + элемент.Ключ + " завершен аварийно! " + Строка(МассивЗаданий[0].ИнформацияОбОшибке.Описание), СтатусСообщения.Важное); СоответствиеЗаданий.Удалить(элемент.Ключ); КонецЕсли; КонецЦикла; Если СоответствиеЗаданий.Количество() = 0 Тогда ОтключитьОбработчикОжидания("ВывестиРезультат"); КонецЕсли; КонецПроцедуры КоличествоПотоков = 10; [/code] Вторая процедура периодически просматривает фоновые задания на предмет завершения (нормального или аварийного) созданных. |
|||
1
ДенисЧ
14.04.15
✎
08:54
|
по идее - неправильное поведение.
Но поиграйся с гибкими блокировками |
|||
2
shuhard
14.04.15
✎
08:56
|
(0) [Но долго, т.к. элементов многовато.]
поставь загрузка = Истина и не трогай блокировки, УПП 1.3.12.1 этого не переживёт |
|||
3
ДенисЧ
14.04.15
✎
08:57
|
(2) Не проснулся?
НоменклатураОбъект.ОбменДанными.Загрузка = Истина; |
|||
4
бомболюк
14.04.15
✎
08:59
|
работа я так понял разовая - может напрямую в SQL тогда? Или, если можно, удаляем реквизит в конфигураторе и создаем заново ;-)
В модуле объекта справочника "Номенклатура" ничего интересного нет, что могло бы вызывать блокировки? |
|||
5
unit_3q
14.04.15
✎
09:00
|
Пока играюсь на экземпляре базы для разработки и отладки, так что тут пока можно все. Можно и первый вариант обработки оставить, просто хочу понять в чем проблема.
|
|||
6
unit_3q
14.04.15
✎
10:26
|
(4) Спасибо за рекомендацию. В модуле объекта справочника номенклатуры даже при записи с параметром ОбменДанными.Загрузка = Истина осуществлялся заход в обработчик процедуры "ПриЗаписи". А там... код для взаимодействия с базой Oracle, писанный незнамо когда (еще до меня программисты писали). Прописал возврат, если ОбменДанными.Загрузка = Истина. Проблема исчезла.
12 тыс. записей в десяти потоках обрабатываются менее чем за 1 минуту. Вариант с работы напрямую через SQL не рассматривал. Там еще много чего надо сделать. Вообще задача поставлена отключить учет по сериям номенклатуры и вычистить информацию о сериях из базы. Было желание сделать все в одной обработке. Оно реализовано. А мультипоточность - это типа гимнастики для ума. Всем спасибо. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |