|
|||||||
Как ускорить 1С – Многопоточная обработка данных
Время создания: 20.09.2016 08:13
Автор: Бурмистров Андрей
Текстовые метки: 1c.multitasking
Раздел: Программирование - 1с - multitasking
Запись: xintrea/mytetra_anatolean/raw/master/base/1474348435gpmj7esjv6/text.html на bitbucket.org
|
|||||||
|
|||||||
Чем будет для Вас полезна эта статья:
Периодически возникает необходимость в ускорении некоторых участков кода, в которых при беглом ознакомлении нет потенциала для ускорения. Рассмотрим в качестве примера выгрузку и/или загрузку большого количества данных. В данном случае «планкой производительности» зачастую выступает непосредственно производительность аппаратных средств. При этом сами процедуры загрузки-выгрузки выполняются достаточно длительное время, часто измеряемое в часах. Не все знают, что в платформе «1С: Предприятие 8» часть операций можно выполнять параллельно, путем одновременного выполнения в несколько потоков. Такая многопоточная обработка вполне применима в случае, когда нужно обработать независимые блоки данных. В частности, создать большой объем элементов данных, осуществить проведение документов, не пересекающихся по значениям набора измерений, сделать массовое обновление элементов справочников, выполнить загрузку данных в регистры и т.д. Для примера рассмотрим задачу: необходимо провести обновление реквизита «Цена» для всех элементов справочника «Товары». Количество элементов справочника «Товары» равно 100 000. Самым простым и очевидным решением выступает нижеприведенный код обработки, который быстро пишется, но при этом очень долго работает:
&НаСервере Процедура ОбновитьЦену() ВремяНачала = ТекущаяДата();
Запрос.Текст = "ВЫБРАТЬ | Товары.Ссылка |ИЗ | Справочник.Товары КАК Товары";
ТоварОбъект = ТекСторока.Ссылка.ПолучитьОбъект(); ТоварОбъект.Цена = ТоварОбъект.Цена*Наценка; ТоварОбъект.Записать(); КонецЦикла;
В нашем случае обработка выполнялась 1 187 секунд или 19,7 минуты. Теперь воспользуемся многопоточным выполнением программного кода. Перепишем код обработки следующим образом: &НаСервере Процедура ОбновитьЦену() Запрос.Текст = "ВЫБРАТЬ | Товары.Ссылка |ИЗ | Справочник.Товары КАК Товары"; ТаблицаТоваров = Запрос.Выполнить().Выгрузить();
ЧислоПотоков = 8;
РазмерПорции = Цел(ЧислоСтрокаВТаблице/ЧислоПотоков);
МассивЗаданий = НовыйМассив;
// разные потоки обрабатывают разные части таблицы ИндексНачала = (НомерПотока - 1)*РазмерПорции;
// если это последний поток, то он обрабатывает все оставшиеся данные // т.к. число потоков может не быть кратно количеству строк в таблице РазмерПорции = ЧислоСтрокВТаблице -(ЧислоПотоков*РазмерПорции)+РазмерПорции; КонецЕсли;
НаборПараметров = Новый Массив; НаборПараметров.Добавить(ТаблицаТоваров); НаборПараметров.Добавить(ИндексНачала); НаборПараметров.Добавить(РазмерПорции);
Задание = ФоновыеЗадания.Выполнить("ОбщийМодуль1.ОбновитьЦенуТовара", НаборПараметров);
МассивЗаданий.Добавить(Задание);
Если МассивЗаданий.Количество() > 0 Тогда Попытка ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий); Исключение // действия в случае ошибки КонецПопытки; КонецЕсли;
КонецПроцедуры
Процедура ОбновитьЦенуТовара (ТаблицаТоваров,ИндексНачала,РазмерПорции) Экспорт
// обновляем цену только для определенной части таблицы Для Сч = 1 По РазмерПорцииЦикл Индекс = ?(Сч=1,ИндексНачала,Индекс+1); ТоварОбъект = ТаблицаТоваров[Индекс].Ссылка.ПолучитьОбъект(); ТоварОбъект.Цена = ТоварОбъект.Цена * Наценка; ТоварОбъект.Записать(); КонецЦикла; КонецПроцедуры
В нашем случае использовалось восемь потоков, обновление цен было выполнено за 859 секунд или 14,3 минуты. То есть обработка одной и той же Таблицы Значений параллельно разными потоками приводит к выигрышу в скорости. Код выполнялся на виртуальной машине с одним процессором без RAID массивов. На реальном и хорошем «железе» выигрыш в скорости будет существенно больше. Заметим, что данную задачу можно решить по-другому, мы привели лишь один пример реализации. Важно! Не нужно устанавливать слишком большое количество потоков, так как большого прироста скорости вы от этого все равно не получите, а стабильность работы может нарушиться. Наилучшим будет использование 8-10 потоков, а их оптимальное количество можно определить экспериментально. Попробуйте самостоятельно провести эксперимент, база и обработки в приложении к статье. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|