Многопоточность в 1С, клиент-серверный вариант
Разработка - Механизмы платформы 1С
Пролог.
Т.к. тема вызвала значительный интерес, хотелось бы дополнить ее ссылкой на раздел сайта Intel для разработчиков. В частности там говорится следующее:
Когда-то параллельное программирование было уделом только тех одиночек, которых интересовали задачи для огромных суперкомпьютеров. Но теперь, когда на многоядерных процессорах начали работать обычные приложения, параллельное программирование быстро становится технологией, которую должен освоить и уметь применять любой профессиональный разработчик ПО.
Введение.
Итак, многопоточность - это возможность выполнять несколько программ (потоков, threads) одновременно. Клиент-серверная архитектура 1С позволяет реализовать данную функцию через механизм фоновых заданий, при этом можно добиться существенного повышения производительности решений на платформе 1С.
Многопроцессорные сервера 1С являются устоявшимся фактом. Загрузка процессоров на серверах даже при достаточно интенсивной работе пользователей не редко держится на уровне 20-30%, т.к. клиентская часть 1С берет на себя функционал как минимум по отображению форм и, возможно, какую-то дополнительную нагрузку. В толстом же клиенте нагрузка на нее еще выше. Отсюда следует, что на серверах 1С существует неиспользованный вычислительный ресурс, который можно утилизировать.
Как это работает?
Для того, чтобы заставить 1С что-то делать параллельно, нужно обрабатываемые данные разбить на куски и постепенно скармливать создаваемым для этого потокам. Архитектурно это состоит из механизма получения порции данных - источника данных, механизма обработки данных - рабочей процедуре, и управляющей функции.
В итоге у нас вырисовывается такая схема:
Управляющая процедура -> Поставщик данных (запрос) -> Фоновое задание (порция данных) -> Отчет о выполнении -> Управляющая процедура.
Математическая модель будет выглядеть так:
- Получаем данные для обработки.
- Задаем количество фоновых заданий.
- Создаем массив для хранения фоновых заданий.
- Если количество стартованных фоновых заданий меньше, чем задано - п.5., иначе п.7.
- Стартуем фоновое задание и передаем ему оговоренное количество данных.
- Еще есть данные? Да - п.4, нет - выход (или подождем через ОжидатьЗавершения(МассивФЗ), после чего выйдем).
- Проверяем, есть ли в массиве задание, которое уже отработало. Если есть - п.5., иначе п.7.
Практическая задача.
Допустим, нам надо заполнить новый реквизит регистра сведений в соответствии с определенными условиями, которые могут быть отбором компоновки данных.
Дано:
- Регистр сведений "СферическиеКони" с измерением "Конь" (справочник "Кони") и ресурсом "ПлотностьСреды" (число 15,10) .
- Мы добавили параметр "СопротивлениеСреды", характеризующий сопротивление среды при максимальной скорости данного коня. Именно его и надо заполнить.
Предположим, что коней у нас много и заполнение без многопоточности займет много времени.
Опишем для начала рабочую процедуру:
Процедура ЗаполнитьСопротивлениеСреды(ИсточникДанных) Экспорт
Для Каждого Ст ИЗ ИсточникДанных Цикл
Рег = РегистрыСведений.СферическиеКони.СоздатьМенеджерЗаписи();
Рег.Конь = Ст.Конь;
Рег.Прочитать();
Рег.СопротивлениеСреды = ПолучитьСопротивлениеСредыДляКоня(Ст.Конь.МаксСкорость, Ст.Конь.Радиус, Рег.ПлотностьСреды);
Рег.Записать();
КонецЦикла;
КонецПроцедуры
Данная процедура должна располагаться в общем модуле и быть экспортной, т.к. именно ее будет вызывать управляющая процедура, формируя фоновые задания.
Теперь опишем управляющую процедуру:
В принципе, управляющая процедура может и не быть процедурой - она может продолжить код получения данных
МассивФЗ = Новый Массив;
КоличествоЗаданий = 10;
КоличествоДанныхДляЗадания = 100;
МассивДанныхЗадания = Новый Массив;
Для Каждого Ст ИЗ ИсточникДанных Цикл
МассивДанныхЗадания.Добавить(Ст);
Если МассивДанныхЗадания.Количество() = КоличествоДанныхДляЗадания Тогда
Пока МассивФЗ.Количество() = КоличествоЗаданий Цикл
Для Каждого ФЗ ИЗ МассивФЗ Цикл
// не помню, как получается задание, но как-то так - нет под рукой 1С
// смысл в том, чтобы проверить статус у запущенного задания, и если он не активен - освободить место в массиве ФЗ
Если НЕ ФоновыеЗадания.ПолучитьФоновоеЗаданиеПоГуид(ФЗ).Статус = СтатусыФЗ.Активно Тогда
МассивФЗ.Удалить(МассивФЗ.Найти(ФЗ));
Прервать; // выйдем из "бесконечного" цикла, когда хотябы одно из заданий закончилось
КонецЕсли;
КонецЦикла; // ФЗ
КонецЦикла; // КоличествоФЗ
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(МассивДанныхЗадания);
ФЗ = ФоновыеЗадания.Выполнить("ОбщийМодуль.ЗаполнитьСопротивлениеСреды", МассивПараметров);
МассивФЗ.Добавить(ФЗ.ГУИД);
МассивДанныхЗадания = Новый Массив;
КонецЕсли; // КоличествоДанныхДляЗадания
КонецЦикла;
Если МассивДанныхЗадания.Количество() > 0 Тогда
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(МассивДанныхЗадания);
ФЗ = ФоновыеЗадания.Выполнить("ОбщийМодуль.ЗаполнитьСопротивлениеСреды", МассивПараметров);
КонецЕсли;
Собственно, что мы сделали? Создали массив заданий и определили параметры обработки (количество потоков, количество данных в потоке). Далее заполнили массив данными, проверили, есть ли свободное место в массиве, если нет - дождались, и передали в фоновое задание для обработки. После чего поместили ГУИД ФЗ в массив.
Заключение.
Многопоточные вычисления все больше будут использоваться в дальнейшем, т.к. процессорная архитектура достигла пределов роста вверх по частоте - теперь она растет вширь по количеству ядер, объему памяти, емкости накопителей. Все это должно привести к прогрессу в области параллельных вычислений.
Вступайте в нашу телеграмм-группу Инфостарт
мультипоточность многопоточность параллелизм
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Механизмы платформы 1С Разработчик Бесплатно (free)
Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?
16.07.2025 45648 TitanLuchs 109
Работа с интерфейсом WEB-интеграция Механизмы платформы 1С Бесплатно (free)
Веб-интерфейсы повышают качество внешнего вида приложений 1С, предсказуемы с точки зрения верстки, позволяют организовать удобные и высокопроизводительные рабочие места для пользователей. Расскажем об особенностях разработки веб-интерфейсов на React внутри 1С, двустороннем взаимодействии 1С и JavaScript, а также сборке веб-приложения в одностраничный файл.
19.06.2025 18661 zeegin 15
Механизмы платформы 1С Работа с интерфейсом Разработчик Стажер 1С:Предприятие 8 Бесплатно (free)
Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).
03.02.2025 26021 bayselonarrend 127
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.
30.01.2025 33263 user2122906 10
Механизмы платформы 1С Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 Бесплатно (free)
Этот материал познакомит вас с механизмом XDTO (XML Data Transfer Objects) в 1С и научит эффективно использовать его возможности. Мы разберёмся, как работать с XML-схемами, создавать модели данных, манипулировать объектами XDTO, а также сериализовать и десериализовать их в XML. Вы узнаете, как использовать XDTO для интеграции с внешними системами, избегать типичных ошибок и оптимизировать код. К концу вы будете уверенно применять XDTO для решения сложных задач обмена данными и автоматизации процессов.
17.01.2025 55714 user2122906 13
Механизмы платформы 1С WEB-интеграция Разработчик 1С:Предприятие 8 Бесплатно (free)
В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.
14.01.2025 46760 dsdred 110
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
Особенности "Знач" и разбор документации к нему.
10.01.2025 26436 VAAngelov 60
Механизмы платформы 1С Разработчик Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.
23.06.2024 40432 bayselonarrend 24
В реальной жизни существует масса задач, скорость выполнения которых обратно пропорциональна количеству процессов (если их не больше количества ядер). Операции ввода-вывод, кстати, используют задержки, которые могут утилизироваться многопоточностью.
P.S. Очень интересно было бы увидеть данные по приросту скорости выполнения при использовании приведенного метода многопоточности на реальной базе :)
Пришлось как-то изучить Java. Только самые азы. Так вот там все построено на многопоточности.
Мне кажется правильнее делить задачу на 6-10 больших фрагментов и получать результаты большими порциями. Обработка 6-10 фрагментов в одном потоке, это, согласитесь, не обработка тысяч мелких ответов. Но вот в состоянии ли ЗначениеВСтроку() перенести ТЗ из 50 000 строк и 10-12 колонок числовых данных?
Кстати, ФЗ может иногда отваливаться - вместе с убиваемым менеджером кластера rphost'ом. У нас так печать работает в 5 потоков на Linux-сервера печати на базе CUPS. Т.к. они постоянно вылетали, и до включения полнейшего лога сервака мы не понимали, почему. В итоге сделали регистр, куда клались данные, отсортированные по потокам, и каждые 10 минут запускали задание, которое проверяло, есть ли фоновые задания с определенным именем. Если нет, и в регистре не пусто - запускало по новой и отправляло письмо админам. В итоге нашли проблему - одновременное подключение внешней компоненты печати ШК. Обернули в "мутекс" - все стало стабильно. Как-то отключили "допечатывание" - 2 недели проработало без этого - даже не заметили. Ни одно задание не отвалилось, ни один rphost не умер.
Если Многопоточность Тогда
ЧислоСтрокВТаблице = Результат.Количество();
// объем порции данных для обработки каждым потоком
РазмерПорции = Цел(ЧислоСтрокВТаблице/ЧислоПотоков);
// массив, где будут храниться фоновые задания
МассивЗаданий = Новый Массив;
МассивАдресовВХранилище = Новый Массив;
Для НомерПотока = 1 По ЧислоПотоков Цикл
// определяем индекс для начала обработки данных данным потоком
// разные потоки обрабатывают разные части таблицы
ИндексНачала = (НомерПотока - 1)*РазмерПорции;
Если (НомерПотока = ЧислоПотоков) Тогда
// если это последний поток, то он обрабатывает все оставшиеся данные
// т.к. число потоков может не быть кратно количеству строк в таблице
РазмерПорции = ЧислоСтрокВТаблице-(ЧислоПотоков*РазмерПорции)+РазмерПорции-1;
КонецЕсли;
МассивЗадания = Новый Массив;
АдресВХранилище = ПоместитьВоВременноеХранилище(Неопределено);
Для Счетчик = ИндексНачала По ИндексНачала+РазмерПорции Цикл
МассивЗадания.Добавить(Результат[Счетчик])
КонецЦикла;
// определяем массив параметров для процедуры
НаборПараметров = Новый Массив;
НаборПараметров.Добавить(МассивЗадания);
НаборПараметров.Добавить(ИндексНачала);
НаборПараметров.Добавить(РазмерПорции);
НаборПараметров.Добавить(АдресВХранилище);
// запуск фонового задания
Задание = ФоновыеЗадания.Выполнить("МодульРегламентныхЗаданий.ПолучитьТаблицуНайденных", НаборПараметров);
// добавляем задание в массив, чтобы потом отследить выполнение
МассивЗаданий.Добавить(Задание);
МассивАдресовВХранилище.Добавить(АдресВХранилище);
КонецЦикла;
// проверим результат выполнения фоновых заданий
Если МассивЗаданий.Количество() > 0 Тогда
Попытка
ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий);
Исключение
Предупреждение("Ошибка поиска ссылок");
КонецПопытки;
КонецЕсли;
ВсеНайденные = Новый ТаблицаЗначений;
Для каждого ТекАдресВХранилище Из МассивАдресовВХранилище Цикл
ТекТаблица = ПолучитьИзВременногоХранилища(ТекАдресВХранилище);
Если ВсеНайденные.Колонки.Количество()=0 Тогда
ВсеНайденные = ТекТаблица.СкопироватьКолонки();
КонецЕсли;
Для Каждого ТекСтрокаДанные Из ТекТаблица Цикл
НоваяСтрока = ВсеНайденные.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока,ТекСтрокаДанные);
КонецЦикла;
КонецЦикла;
Иначе
ВсеНайденные = НайтиПоСсылкам(Результат);
КонецЕсли;
ПоказатьИ общий модуль:
Процедура ПолучитьТаблицуНайденных(Результат, ИндексНачала, РазмерПорции, АдресВХранилище) Экспорт
ВсеНайденные = НайтиПоСсылкам(Результат);
ПоместитьВоВременноеХранилище(ВсеНайденные, АдресВХранилище);
КонецПроцедуры
Есть другой путь - процедура ОжиданиеЗавершения(массивФЗ). Но тогда мы теряем асинхронность. Мы запустили 10 заданий, они могут выполняться разное время, но ожидая завершения всех заданий мы теряем в производительности. надеюсь, теперь всем все понятно.
Если управляющая функция находится на клиенте, то стоит присмотреться к ПодключитьОбработчикОжидания, а если на сервере (это ваш случай), то к ФоновыеЗадания.ОжидатьЗавершения с выставленным таймаутом
// Старый добрый WaitForMultipleObjects() в исполнении 1С вышел не айс. //
Вот такие "добрые дяди" с ожиданием завершения и удивляются, почему это эффективность маловата. Стоит также иметь ввиду, что получение фонового задания ждет ответа от сервера - в это время никаких инструкций не выполняется.
Во-вторых, использование бесконечного цикла не является моветоном в программировании. Читайте тут:
/////////////////
Роль бесконечных циклов в Тьюринг-полноте языков[править | править вики-текст]
Любой цикл можно представить как бесконечный цикл, в теле которого есть проверка условия выхода и команда выхода из цикла.
Любая программа может быть написана при помощи:
бесконечных циклов;
команд выхода из цикла;
операторов ветвления (if-then);
последовательностью команд, исполняемых одна после другой;
Примечание: обратите внимание, что универсальный оператор GOTO (безусловный переход) не нужен, а достаточно специального оператора выхода из цикла, при этом, в случае n вложенных циклов потребуется n специальных операторов выхода из цикла (кроме небольшого количества языков с расширенным синтаксисом операторов выхода) или один оператор GOTO и одна метка.
/////////////////////////////
rtnm. учите мат.часть - это очень полезно. И запомните, если Вас всегда хвалят и всегда с Вами согласны - вы не развиваетесь. Я объективную развернутую критику крайне приветствую, но Ваше "Управляющая функция жестко зациклена - не стоит демонстрировать такой код." просто показывает, что в программировании, увы, Вы ничего не смыслите. Уж извините, но как есть.
- запуск внешнего приложения - ФЗ будет ждать, пока оно завершит работу.
- запрос - ФЗ будет ждать, пока возвратятся данные.
- COM-объект - ФЗ будет ждать ответа.
- 1С тоже может повесить задание, но я таких примеров не встречал.
Должно быть как в NET -
1. определил спектр видимости переменных (в каждом потоке свой экземплар, или указанные потоки работают с одними и теми же переменными)
2. определил функции или процедуры, которые будут запускаться
3. запустил параллельно процедуры, с возможностью передачи управления по исключению или если всё хорошо (continuous)
4. ожидаем завершения нужных процедур (не в цикле!!!)
Куда обычно скидывают состояния? Отдельную таблицу создавать как-то некрасиво. Хранилище общий настроек?
вы что с телефона запостили? Ехали в маршрутке и решили, а не запостить ка мне про 1с в инфостарт.. ? (не смотря на то что с памятью у вас сомнения!)
Это не серьезно, ради чего это было сделано?
Я лично после этого комментария потерял уровень серьезности намерений вложить вклад в развитие программистов ищущих решения, не хотелось бы чтобы вы были примером им. Если сможете то старайтесь!
Более того, стараюсь, чтобы тот, кто осилит чтение статьи, смог это сделать, не тупо копируя код, а понимая, что этот код делает. Для этого нужно, чтобы код был написан не автором и скопирован, а читателем.
Статья рассказывает о многопоточности, о принципах, а не дает код, который любой дурак скопирует куда-то, а потом будет гадать, почему же у него что-то не получилось. Статья излагает мат.часть, которую нужно прежде всего понять. И код получения фонового задания - это не тот код, который должен вызывать подобную реакцию, а то напрашивается мысль, а понял ли читатель вообще хоть что-то?
upd Все отрабатывает, но обычным способом все равно выходит быстрее. Вроде и логично - я делаю то же самое что просто создавая элемент, но фоновое всегда одно. те как-будто они по очереди создают.
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 370384
Создание 21.06.15 20:41
Обновление 21.06.15 20:41
Просмотры 67405
Загрузки 0
Рейтинг
88
Комментарии 57
Код открыт Не указано
Рубрики Механизмы платформы 1С
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация 1C:Бухгалтерия
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)