Məzmuna keç
Tez Base

Ускорит ли внешняя компонента на C++ ваш код 1С: как посчитать до того, как писать

· Dərc edilib:

Запросы и скорость

Расчёт крутится минуту, разбор файла тормозит обмен, поиск дублей в справочнике не дождаться. Первая мысль опытного разработчика: вынести узкое место во внешнюю компоненту на C++ (технология Native API). Интерпретатор 1С медленный, машинный код быстрый, значит будет быстрее.

Иногда так и выходит, причём в сотни раз. А иногда компонента получается медленнее кода, который заменила, и неделя работы уходит в минус. Различить эти случаи можно заранее, без единой строки на C++. Для этого нужно знать три вещи: как подключена компонента, сколько 1С будет готовить данные для неё и разбирать её ответ, и есть ли у задачи готовая платформенная функция.

Ниже методика с цифрами. Они взяты из замера 31 задачи: каждую мы решили на встроенном языке (до трёх вариантов, от наивного до лучшего) и своей компонентой, результаты всех вариантов сверены по MD5, время снято от начала до конца с раскладкой по фазам. Стенд: Windows 10 x64, Core i7-9750H, 16 ГБ, платформа 8.3.27.1606, клиент-серверная база, всё исполняется на сервере, сервер без отладки.

Время компоненты складывается из трёх частей

время компоненты = подготовка данных в 1С + вызов (передача туда и обратно + расчёт) + разбор ответа в 1С

Компонента принимает и возвращает только строки, числа и двоичные данные. Структуру, массив или таблицу значений она вернуть не может. Значит, если на входе у вас таблица, 1С сначала превращает её в текст, а если результат нужен коллекцией, 1С собирает её из текста ответа. Обе операции идут на встроенном языке, то есть на той же медленной скорости, от которой вы бежите.

Как это выглядит в цифрах, 100 000 записей, компонента в процессе 1С:

ЗадачаЛучшая 1СКомпонента всегоПодготовкаВызовРазбор ответа
JSON в массив структур590 мс (ПрочитатьJSON)1 133 мс052 мс1 003 мс
JSON в таблицу значений966 мс1 480 мс062 мс1 389 мс
JSON из массива структур540 мс (ЗаписатьJSON)703 мс656 мс42 мс0
сумма и количество по ключу в JSON1 105 мс43 мс043 мс0,2 мс

Компонента в первых трёх строках работала 42-62 мс. Проиграла она из-за того, что до и после неё делала 1С. В последней строке на вход идёт готовый текст, на выход несколько чисел, и выигрыш 26 раз.

Отсюда первое правило оценки: прикиньте, сколько стоит подготовка и разбор на встроенном языке. Если это больше, чем лучший вариант решения задачи целиком на 1С, компонента не поможет при любом C++.

Цена вызова: одна строка подключения меняет её в 30 раз

На 8.3.27 у ПодключитьВнешнююКомпоненту есть четвёртый параметр типа ТипПодключенияВнешнейКомпоненты со значениями Изолированно и НеИзолированно. Без него компонента на нашем сервере вела себя ровно как с явным Изолированно: работала в отдельном процессе, и каждый вызов шёл через обмен между процессами.

// Компонента в процессе 1С: вызов почти бесплатный,
// но сбой компоненты роняет рабочий процесс вместе с сеансами
Подключена = ПодключитьВнешнююКомпоненту(Адрес, "Nativka", ТипВнешнейКомпоненты.Native,
	ТипПодключенияВнешнейКомпоненты.НеИзолированно);

Сколько стоит граница в каждом режиме:

ЧтоИзолированноВ процессе 1С
пустой вызовоколо 123 мксоколо 4 мкс
передать 1 млн символов90 мс1,1 мс
получить 1 млн символов38 мс2,4 мс
1 МБ двоичных данных туда и обратно205 мс1,4 мс

Для сравнения, пустая процедура на 1С стоит около 1,4 мкс на вызов. Компонента в процессе 1С дороже её втрое, изолированная - примерно в девяносто раз.

Эти четыре строки дают второй инструмент оценки. Посчитайте, сколько текста уйдёт в компоненту и сколько вернётся, умножьте на цену из таблицы. Если в изолированном режиме одна передача уже съедает время лучшего варианта на 1С, писать компоненту под этот режим бессмысленно.

Про изолированный режим ещё два наблюдения на этом сервере, оба стоили нам полдня. Двоичные данные больше 163 803 байт приходят в изолированную компоненту строкой Base64 в варианте для адресов, а не двоичными данными; обратно двоичные данные больше 70 182 байт возвращаются тоже строкой. И изолированная компонента, однажды подключённая в базе, не подменялась новой сборкой даже под другим именем подключения и другим именем DLL, пока не перезапустили сервер. В процессе 1С обоих эффектов не было.

На 8.3.20 этого параметра в платформе нет вовсе. Как там ведёт себя граница, мы не мерили.

Выбор режима: скорость против устойчивости

Изоляция придумана не зря. Падение компоненты в отдельном процессе не роняет рабочий процесс 1С, а в процессе 1С роняет вместе со всеми сеансами, которые на нём живут. Поэтому правило такое:

  • компонента своя, покрыта тестами и не бросает исключений через границу: НеИзолированно, и вы получаете цифры из правой колонки;
  • компонента чужая или сырая: изоляция, и тогда выигрывают только задачи с маленьким входом и большим расчётом (о них ниже).

Какие задачи выигрывают и с какого объёма

Сводка по всем группам. “Окупается с” - наименьший объём из лестницы замера, на котором компонента в процессе 1С обогнала лучший вариант на 1С.

ЗадачаОбъём замераЛучшая 1СВ процессе 1СИзолированноОкупается с
рюкзак 0/1, 100 предметоввместимость 50 0006 252 мс5 мс4,8 мс1 000
сумма квадратов в цикле10 млн8 946 мс7,5 мс7,5 мс100 000
Монте-Карло, число пи1 млн точек3 115 мс8,8 мс8 мс100 000
нечёткие дубли, Левенштейн до 21 000 наименований1 403 мс6 мс16 мс100
построчное сравнение текстов20 000 строк1 205 мс7,5 мс166 мс1 000
расстояние Левенштейна10 000 пар4 602 мс39 мс119 мс100
переложить JSON с переименованием полей100 000 записей1 376 мс49 мс1 612 мс1 000
итоги по ключу в JSON100 000 записей1 105 мс43 мс1 253 мс1 000
итоги дат и чисел из текста1 млн строк2 959 мс165 мс2 055 мс10 000
50 подстрок в тексте10 млн символов832 мс229 мс2 799 мс100 000
Base64, декодирование50 МБ1 149 мс324 мсдольше 10 с1 млн байт
разбор CSV в массив массивов100 000 строк962 мс375 мс1 712 мс1 000
SHA-256100 МБ469 мс505 мс-паритет
20 массовых замен10 млн символов253 мс136 мс3 884 мс100 000
сортировка чисел1 млн2 701 мс3 094 мс4 148 мсне окупается
регулярное выражение10 млн символов440 мс3 476 мс5 322 мсне окупается
линейная регрессия100 000 точек173 мс268 мс356 мсне окупается
число в строку, вызов на каждое1 млн1 219 мс7 197 мс-не окупается

Из таблицы складываются три типа задач.

Мало данных на входе, много арифметики. Динамическое программирование, перебор, моделирование, попарные расстояния. Компонента выигрывает в десятки и сотни раз в любом режиме, окупается уже на сотнях элементов. Рюкзак, Монте-Карло и матрицы почти не чувствуют изоляцию.

Текст на входе, короткий итог на выходе. Агрегат по JSON, поиск по тексту, разбор дат и чисел с суммированием, сравнение текстов. В процессе 1С выигрыш от 2,5 раза у CSV до 28 у JSON, у сравнения текстов 160. В изолированном режиме он пропадает: десятки миллисекунд расчёта тонут в секунде передачи текста между процессами.

Результат нужен коллекцией или задача уже решена платформой. Разбор JSON в структуры, таблица значений, сортировка, регулярки, хеш. Здесь компонента проигрывает или идёт вровень: либо время съедает сборка коллекции на 1С, либо платформенная функция уже работает в машинном коде. Регулярное выражение в 8 раз медленнее, потому что std::regex уступает движку платформы, и СтрНайтиВсеПоРегулярномуВыражению (с 8.3.23) здесь вне конкуренции.

Где компонента не нужна совсем

Самая дорогая ошибка - писать компоненту под задачу, у которой уже есть штатная функция. CRC32 одного мегабайта самописным кодом на встроенном языке занимает 6-7 секунд, ХешированиеДанных - около миллисекунды. Регулярки, паузу, распаковку RAR и 7z, буфер обмена, WebSocket платформа научилась делать в 8.3.22-8.3.27, и многие компоненты под эти задачи потеряли смысл. Список с проверкой, где какая замена работает, мы собрали отдельно: что заменить штатным в 8.3.22-8.3.27.

Вторая ошибка - вызов компоненты в цикле на каждый элемент. Возвести в квадрат 100 000 чисел на 1С заняло 95 мс, тем же циклом с вызовом компоненты на каждое число - 546 мс в процессе 1С и 7 930 мс изолированно. Компоненте надо отдавать работу пачкой: весь текст, весь массив, один вызов.

Потоки и точность

Внутри одного вызова компонента может распараллелить работу, чего во встроенном языке нет совсем. Монте-Карло на 50 млн точек: 372 мс в один поток, 42 мс на всех двенадцати потоках шестиядерного процессора, в 9 раз быстрее. А нечёткие дубли на 3 000 наименований ускорились только с 31 до 11 мс: работы мало, запуск потоков съедает выигрыш. Число потоков стоит делать параметром с умолчанием 1: компонента, которая без спроса займёт все ядра сервера, мешает остальным сеансам.

Точность - отдельный повод остановиться. Линейная регрессия на миллионе точек не прошла сверку результатов: 1С считает десятичными числами и дала свободный член 49,425190, компонента в double - 49,425202. Для денег и количеств в учёте перенос расчёта в double без такой сверки опасен.

Чек-лист перед тем, как писать компоненту

  1. Есть ли платформенная функция? Хеш, JSON, регулярки, сортировка коллекции, архивы. Если есть, компонента не нужна.
  2. Сколько данных уходит и возвращается? Умножьте объём на цену границы из таблицы для вашего режима.
  3. Нужен ли результат коллекцией? Если да, оцените время сборки этой коллекции на 1С. Часто оно одно больше всего остального.
  4. В каком режиме будет работать компонента? Если изолированно, выигрывают только задачи с малым входом.
  5. Не вызывается ли она в цикле? Пачка вместо поэлементных вызовов.
  6. Совпадает ли результат? Сверка с вариантом на 1С на тех же данных, особенно для дробных чисел.

Наши цифры сняты на одной машине под Windows. На Linux мы не мерили, и на вашем сервере абсолютные миллисекунды будут другими. Чтобы не гадать, мы собрали бенчмарк в виде внешней обработки: компонента лежит внутри макетом, 31 тест прогоняется на вашем сервере в обоих режимах подключения, результат сохраняется в JSON рядом с описанием окружения. Десять выигравших ядер из таблицы выше доступны из неё как обычные функции.

Если узкое место уже найдено, а разбираться, где именно уходит время, некогда, напишите нам в WhatsApp: замерим по фазам и скажем, что даст больше, оптимизация на встроенном языке, платформенная функция или компонента.

Медленное место в 1С, и непонятно, поможет ли компонента на C++

Замерим ваше узкое место по фазам, скажем, где время на самом деле, и предложим ускорение: на встроенном языке, платформенным средством или компонентой

Qiyməti
150 000 ₸-dənlayihə üçün; vergilərsiz; pulsuz auditdən sonra sabitlənir
Müddət
от 2 дней

Yazmaq tezdir? Özünüz ölçün

Бенчмарк: код 1С против внешней компоненты на C++ на вашем сервере

Emalı aç

INFOSTART TECH EVENT 2026: конференция для 1с-специалистов. если собираетесь, регистрируйтесь по нашей ссылке. Регистрация →

Bunu da oxuyun

Почему нейросеть повторяет одно и то же: карта внимания модели, снятая на встроенном языке 1С

Модель смотрит в вопрос, пока пишет первые три символа ответа, а дальше почти только на себя. Если выключить у неё одну голову внимания из четырёх, верных ответов не остаётся, а больше трети ответов уходят в повтор вроде "стстстст". Разбираем, как снять карту внимания функцией на сорок строк, что она показала на сорока вопросах и что из этого следует для тех, кто работает с большими моделями.

Нейросеть для проверки кода 1С: как проверить её на своём коде до внедрения

Прежде чем отдавать нейросети ревью кода 1С, её стоит принять на своём коде: у нас одна и та же локальная модель нашла 11 дефектов из 13 на учебных процедурах и 0 из 5 на рабочих. Разбираем порядок приёмки: какие два числа считать, из чего собрать проверочный набор, как поднять стенд без интернета и по каким признакам видно, что замер врёт.

Технологический журнал 1С: как собрать данные о тормозах

План короткого сбора технологического журнала 1С: вопрос, события, окно наблюдения и проверка причины. Как отличить ожидание от выполнения.