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




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

58 Comments

  1. panvartan

    Используем утечки памяти по назначению

    Reply
  2. kolya_tlt

    Имеет смысл кэшировать данные, полученные из базы данных, внешних источников данных или путем сложных (ресурсоемких) вычислений. Причем в ряде случаев, даже значения, полученные из базы данных, не стоит кэшировать, если выгода от их кэширования – неочевидна.

    https://its.1c.ru/db/v8std#content:-2145782923:hdoc

    Reply
  3. Dream_kz
    Баг это или фича непонятно, но знать о нем не помешет

    Просто особенность, первым вызовом получим ссылку на элемент в области памяти, поменяем ее значение, а вторым вызовом получим ссылку на эту же область памяти, естественно что значение по ссылке уже будет измененное.

    Статья хорошая, но не раскрыты собственно сами модули, отличия при хранении на время вызова и на время сеанса, время хранения значений на сервере на время сеанса (около 6 минут), а так же то, что это не панацея, и допустим от получения булевых констант таким образом, выигрыша будет мало.

    Reply
  4. vandalsvq

    Это не баг, скорее все таки фича. На прошлой партнерке 1С рассказывали, объекты возвращаются по ссылке, т.е. не копия структуры, массива и т.д., а ссылка на область памяти по сути (косвенно можно сделать такие выводы также из статьи про системы диагностики из «зазеркалья» тынц).

    Так что, не рекомендуют так обновлять — что ж поделать, не будем. Ну если только совсем чуть-чуть, ну самую капелюшечку )))))

    Reply
  5. headMade

    (3)в чем будет принципиальное отличие при чтении и кешировании значений булевых констант?

    Reply
  6. nicxxx

    (5)Очевидно же, что чтение будет обращаться к таблице констант в базе, а использование кэша заменяет обращение к базе обращением к памяти, что несколько быстрее, раз в 100 примерно.

    Reply
  7. Dnki

    Про механизм знаю, но пользуюсь.

    * Первая причина: неудобно 1С сделала признак — на весть модуль. Нужно было бы сделать директиву к функции, аналогично «export». По-моему, сам бог велел ввести такое свойство, явно написанное программистом, а не легко устанавливаемая/ снимаемая птичка. Я поясню: написал я модуль «РаботаСЧемТО». В нем собраны ф-ии по одной теме. Из них только одна нужна с кэшированием. Ясно дело, можно разбить, но краше от этого программа не будет.

    * Механизм очень уж неявный. Я не знаю, когда сбросится кэш. Самому дать команду сброса — сбрасывается все. Короче, все что не написано программистом, вызывает сомнение в работе, особенно в след. релизах. Когда мне понадобилось, я сам написал. Например, кэш курсов валют сбрасываю в начале формирования отчета. Некоторые данные, часто используемые, но практически не меняемые, читаются в глобальный объект только при запуске.

    * В задаче повторных значений лучше бы 1С решило для меня такую задачу: по анлогии с «С» иметь параметр объявления переменных Static. Такие переменные, являясь переменными процедуры, сохраняются в памяти между вызовами процедуры.Вот это был бы классный кэш!

    Reply
  8. starik-2005

    «Есть многое на свете, друг Горацио, что и не снилось нашим мудрецам» (с) Шекспир.

    К чему это я? А к тому, что иногда (и даже часто) некоторые моменты при кешировании объектов таким способом могу привести к непредсказуемым последствиям. В частности, от длины «ключа» может зависеть жизнеспособность кешированного объекта при последующем его обновлении. Т.е. типа получаете объект тОбъект = ОбщМодПовтИсп.ПолучитьОбъект(«ХХХУУУZZZ»), а он вам так раз….

    Reply
  9. chea06

    (6)не факт

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

    Reply
  10. Dream_kz

    (5) Принципиальных отличий не будет, но как сказал я ранее, и дали ссылку в (9) эффекта будет мало.

    Reply
  11. herfis

    Хоть и РТФМ, но плюсанул. Может, кому-то статья поможет начать использовать эту функциональность.

    Сам использую достаточно широко — в ряде случаев помогает одновременно и упростить код и повысить его эффективность.

    Единственный совет — хорошо подумайте, точно ли кэшируемая информация является условно-постоянной (является ли критичным доступ к обновленным в течение сеанса данным).

    Reply
  12. Anton64

    Ссылку нельзя передавать параметром?

    Reply
  13. herfis

    (12) Ссылку можно.

    Reply
  14. tormozit

    Неплохо бы еще не только про «на время сеанса» но и про 20 минутное время жизни значений в кэше упомянуть. Эта особенность на некоторые способы использования влияет сильно.

    Reply
  15. xReason

    Можно возвращать данные с типом ФиксированнаяСтруктура, ФиксированныйМассив и т.д.

    Тогда фича от 1С в виде изменяемого значения не будет работать

    Reply
  16. herfis

    (14) Кэш, как и обещано, живет до конца сеанса. Через 20 минут без использования он просто на диск откочует. И «неожиданности» тут возникнут только с мутабельными значениями, которые невозможно корректно сериализовать. То есть проблемы возникнут, если пытаться использовать кэш как хранилище глобальных серверных переменных произвольного типа. Но да — эту особенность упомянуть стоит однозначно.

    Можно, например, инициализированный COM-объект так держать в памяти сервера. В большинстве случаев ничего страшного, если он пересоздастся после долгого неиспользования. Я по-дефолту так с сервера всякие сторонние соединения поднимаю. Если же пытаться так хранить мутабельные промежуточные результаты, которые терять нельзя, то придется обеспечить их «дергание», чтобы они не потерялись при попытке сериализации. Но это уже совсем изощренные костыли, которых стоит избегать. Лучше оставаться в рамках stateless-модели сервера, пусть и с некоторой потерей эффективности.

    Reply
  17. tormozit

    (16)

    Кэш, как и обещано, живет до конца сеанса.

    Ошибаешься. Тут уже привели ссылку на ИТС. Почитай https://its.1c.ru/db/v8std#content:-2145782923:hdoc

    Reply
  18. herfis

    (17) Смущает примечание «раздел обновлен». Сдается мне, ранее на ИТС я читал совсем другое.

    Reply
  19. herfis

    (17) Хотя и в руководстве разработчика на ИТС тоже самое написано…

    Не хотелось бы принимать во внимание свой маразм, но видимо придется 🙂

    Reply
  20. mefalcon

    (7)>>Я поясню: написал я модуль «РаботаСЧемТО». В нем собраны ф-ии по одной теме. Из них только одна нужна с кэшированием. Ясно дело, можно разбить, но краше от этого программа >>не будет.

    Именно так 1С делает в типовых решениях, добавляя в конец имени модуля, отражающую предметную область использования, суффикс «ПовтИсп»

    https://stimul.kiev.ua/materialy.htm?a=pravila_sozdaniya_obshchikh_moduley

    Reply
  21. herfis

    (20) Более того — это зафиксировано в стайл-гайде 1С по именованию общих модулей.

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

    Клиент, КлиентСервер, Сервер, ВызовСервера, КлиентПовтИсп, СерверПовтИсп — шесть модулей как с куста.

    А могут еще быть ПолныеПрава и Глобальный (но за глобальные надо расстреливать, я считаю).

    Reply
  22. bruho

    Для того, чтоб «сбросить» значения в методе с повторным использованием использую необязательный параметр, в который передаю УИ. Но подходит только для тех случаев, когда явно указываешь вызов с заполненным необязательным параметром.

    Функция МетодСПовторнымИспользованием(ОбновитьЗначение = Неопределено) Экспорт
    
    Время = ТекущаяДата();
    
    Возврат Время;
    КонецФункции
    
    //Время вернет из первого обращения к методу
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = Строка(МетодСПовторнымИспользованием());
    Сообщение.Сообщить();
    
    
    //Время вернет текущее
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = Строка(МетодСПовторнымИспользованием(Строка(новый УникальныйИдентификатор)));
    Сообщение.Сообщить();
    
    
    
    

    Показать

    Reply
  23. Rustig

    (0) я суть статьи не понял. рабочие примеры есть для понимания?

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

    Столкнулся в УТ 10.3 с такой проблемой — в УТ 10.3 появился механизм ПравилаВыборочнойРегистрацииОбъектов (константа),

    который не позволяет переименовывать типовые реквизиты документов.

    Я переименовал в документе ПКО реквизит Основание (Тип Строка), потому что он некорректно заполняется при заполнении на основании другого документа (стандартный параметр Основание процедуры ОбработкаЗаполнения()).

    …Срабатывает процедура ОбработкаЗаполнения, в которую передается параметр Основание (тип ДокументСсылка). В конце концов реквизит документа Основание и параметр Основание пересекаются и дают отрицательный эффект.

    Я переименовал этот реквизит в ОснованиеСтрока — теперь у меня элементарно не проводится документ, выходит ошибка здесь:

    Функция ПолучитьТаблицуРеквизитовРегистрацииШапкиДоИзменения(Объект, СтрокаТаблицыРеквизитовРегистрации)

    ТекстЗапроса = »

    |ВЫБРАТЬ » + СтрокаТаблицыРеквизитовРегистрации.РеквизитыРегистрации

    + » ИЗ » + СтрокаТаблицыРеквизитовРегистрации.ИмяОбъекта + » КАК ТекущийОбъект

    |ГДЕ

    | ТекущийОбъект.Ссылка = &Ссылка

    |»;

    Запрос = Новый Запрос;

    Запрос.Текст = ТекстЗапроса;

    Запрос.УстановитьПараметр(«Ссылка», Объект.Ссылка);

    Возврат Запрос.Выполнить().Выгрузить();

    КонецФункции

    , в запрос тащится СтрокаТаблицыРеквизитовРегистрации.РеквизитыРегистрации, который содержит следующие поля:

    Организация, ВидОперации, Контрагент, ДоговорКонтрагента, ВалютаДокумента, СуммаДокумента, ПринятоОт, Основание, Приложение, Комментарий, ДокументОснование, СтатьяДвиженияДенежныхСредств, СтавкаНДС, НомерЧекаККМ, ПометкаУдаления, Проведен, Номер, Дата, Ответственный, ОтражатьВБухгалтерскомУчете

    То есть таким механизмом разработчики ут 10.3 не позволяют переименовывать типовые реквизиты. Хм, думаю это неправильно.

    может я не туда пишу — поправьте — но это своего рода кэширование — хранение информации о жесткой структуре метаданных конфигурации которую как будто теперь нельзя изменять — валятся родные механизмы

    Reply
  24. gmkushkunov

    (23) Здравствуйте.

    По поводу жесткой структуры не совсем понятно, раз вы переименовали стандартный реквизит значит структура нежесткая, просто надо переписать код где идет обращение к этому реквизиту. Мне кажется Вы сами никогда не программировали в связке СУБД. Если Вы создали в СУБД таблицу а в ней поля, назвали их как то и написали программу, в которой идет обращение к этой таблице и ее полям (т.е. к их именам), протестировали и дали заказчику полностью рабочую программу, а заказчик в свою очередь переименовал стандартные поля в Вашей таблице не исправляя кода программы, где идет обращение к переименованным полям и обнаруживает, что программа перестала работать (выдает ошибки и т.д.) и начинает Вам жаловаться, что Вы не правильно составили программу, как Вы на это посмотрите?

    P.S. на самом деле Вы не в ту тему пишите.

    Reply
  25. Rustig

    (24) я понял вас: пугает что этот список реквизитов засунули в константу с типом Хранилище.

    обычно когда меняют наименование реквизита, прогоняют глобальным поиском места где встречается этот реквизит, и везде поправляют название.

    в нашем случае Глобальный Поиск не нашел Константу в которой спрятан список реквизитов — по сути строка спрятана, саму константу в пользовательском режиме вы тоже не откроете и не увидите — потому тип объекта Хранилище.

    ну и кто так кодит?

    вердикт — что-то намудрили в УТ с механизмами версий, оттуда проблемы происходят

    Reply
  26. Rustig

    (24) я вот не пойму обсуждаемую здесь тему с кэшированием без примеров — какую конкретную задачу пытается решить автор?

    Reply
  27. herfis

    (26) Автор не про конкретную задачу, а про инструмент.

    Если хочется живых примеров — откройте список общих модулей любой современной типовой и глядите в модуля, где в конце «ПовтИсп» в названии.

    Reply
  28. Rustig

    (27) ок, понятно

    а зачем так сложно придумали?

    столько модулей развели — в чем суть?

    Reply
  29. herfis

    (28) Жертвы на алтарь возможности работать через браузер.

    Reply
  30. Rustig

    (29) где-нибудь можно об этом прочитать подробнее?

    Reply
  31. herfis
  32. Darklight

    (15)Возвращать-то можно любое значение. Но, принимать как параметр…. в повторно используемую функцию можно значение типа «Структура». Но НЕЛЬЗЯ типа «ФиксированнаяСтруктура» — вот такой идиотизм. Конечно преобразования «Структура» <-> «ФиксированнаяСтруктура» делается легко — но для повторного использования важна идентичность входных параметров — а тут она теряется!

    Поэтому, лично я предпочитаю вот так (привожу в упрощённом виде) создавать структуры — когда нужна их идентичность (ну и не изменять их потом):

    //Размещено в модуле повторного использования
    функция Структура(ПараметрыСтр, п1=null,п2=null,…здесь ещё 96 таких параметра…,п99=null,п100=null)
    возврат Новый Структура( ПараметрыСтр, п1,п2,…здесь ещё 96 таких параметра…,п99,п100);
    КонецФункции

    Такой подход «гарантирует», что где-то 20 минут структура будет идентична, и её «без опаски» можно дальше передавать как входной параметры в другие повторно используемые функции.

    Конечно, есть и другие варианты достичь идентичности.

    Reply
  33. profiprog1c

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

    Константы.ЛюбаяКонстанта.Получить()

    занимает тысячные доли процента, от времени выполнения реального кода.

    А уж если и нужно в коде часто использовать данные этой константы, то пишем:

    НашаПеременная = Константы.ЛюбаяКонстанта.Получить()

    и дальше использ-уем НашаПеременная

    Самые затраты операции при работе кода — это запросы и вот там нужно оптимизировать.

    Reply
  34. nvv1970

    (17) Перечитал это еще раз (процитирую)

    Закэшированное значение будет удалено из кэша через 20 минут после вычисления или через 6 минут после последнего использования (в зависимости от того, что наступит раньше*). Кроме этого значение будет удалено при нехватке оперативной памяти в рабочем процессе сервера, при перезапуске рабочего процесса и при переключении клиента на другой рабочий процесс. Поэтому если никто «не успел» воспользоваться данными из кэша, то этот ресурс был потрачен зря.

    * Примечание: конкретные цифры могут варьироваться в зависимости от используемой версии платформы 1С:Предприятие.

    На какой-то из недавних версий платформы пытался это поведение протестировать. Ставишь точку в повторяемом модуле. Провалился в модуль — кэш очистился, нет — еще жив.

    Любопытно, что четких временных границ для «последнего использования» не оказалось. Как-то хаотично очистка кэша срабатывала: могло и по 10, и по 20 минут не очищаться при полном бездействии. Но то что очистка происходит — это факт. И это прекрасно )) С содроганием вспоминаю кэш в глобальной переменной.

    ПС: еще не раскрыта тема и приведены примеры «кэша на вызов». Такой вид почти не используется. А между тем тоже стоит о нем помнить. Хватает специфических сложных алгоритмов, когда такой кэш незаменим.

    Reply
  35. Yashazz

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

    Ниочёмка с умным видом. Единственная заслуга статьи, за которую я плюсанул тоже — дискуссия пошла. Вот из дискуссии можно полезное почерпнуть.

    Reply
  36. profiprog1c

    (37) Вы давно 1С занимаетесь или недавно? Давайте уже включайте соображаловку. Учить азам я вас не буду. Константу 1 раз получаете в Процедуре ОбработатьВсе() до цикла, после передаете ее в Процедуру ОбработатьЧтоТо(Ссылка, НашаКонстанта) в цикле. Все просто.

    Еще раз говорю, не нужно пытаться придумывать пользу от получения констант, займитесь программированием наконец.

    Reply
  37. caponid

    (4) Это не баг, и таки не фича — это способ выстрелить себе в ногу))).

    Если хочется возвращать наборы значений — то логичней использовать «фиксированные» — Фиксированная структура и т.д.

    Reply
  38. Hobbit_Jedi

    (38)

    после передаете ее в Процедуру ОбработатьЧтоТо(Ссылка, НашаКонстанта) в цикле

    Ага. Особенно если таких процедур штук двадцать… И они вызывают еще другие процедуры… А те в свою очередь еще процедуры… Везде добавляем аргумент со значением константы и передаем его?…

    Как на мой взгляд, не самое лучшее архитектурное решение. Особенно, если добавленный аргумент в списке аргументов процедур как «не пришей кобыле хвост» смотрится (в том смысле, что не имеет отношения к решаемым процедурами задачам).

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

    Reply
  39. profiprog1c

    (40) Двадцать процедур, тридцать процедур. Давайте придумывайте сферического коня в вакууме. Вы написали конкретный код и я вам написал, как правильно программировать. Еще раз, у меня нет желания вас учить основам программирования. Продолжайте фантазировать на тему констант и двадцати тридцати процедур. Читать забавно

    Reply
  40. Hobbit_Jedi

    (41)

    Вы написали конкретный код и я вам написал, как правильно программировать.

    Я привел ПРИМЕР кода. Естественно, максимально его упростив, т.к. 50 экранов текста никто читать не будет. А если у Вас недостаточно опыта, чтобы с помощью этого простого примера вспомнить реальный код соответствующего масштаба, то помалкивали бы тихонечко. И хотя бы типовые конфигурации полистали (как пример идеального кода они, конечно, не подойдут, а вот как пример сложной иерархии вызовов множества процедур — самое оно будет).

    Успехов Вам в постижении программирования вообще и тонкостей 1С в частности!

    Reply
  41. Hobbit_Jedi

    (41)

    Ну и достану уже «козырную Мантану»….

    Представьте себе, что Вам нужно читать значение константы в обработчике события, например ПриОтправкеДанныхПодчиненному, объекта плана обмена.

    Интересно, где Вы предлагаете определить переменную? Где Вы предлагаете ее инициализировать прочитанным из константы значением? И самое главное — как Вы предлагаете передавать значение этой переменной в обработчик события, который при выгрузке данных на узел вызывается тысячи раз (по количеству выгружаемых объектов данных)?

    Вряд ли Вы сможете ускорить процесс выгрузки не используя кэшируемые общие модули. 🙂

    Reply
  42. nvv1970

    (3) Звезда не заработана.

    Время жизни кэшированных значений — это важнейший момент, отличающий данный механизм от глобальной переменной используемой как КЭШ.

    На ИТС кажется были следующие значения: 20 минут от создания или 6 минут от последнего чтения из кэша.

    …кэш не хранит данные вечно. Закэшированное значение будет удалено из кэша через 20 минут после вычисления или через 6 минут после последнего использования (в зависимости от того, что наступит раньше*). Кроме этого значение будет удалено при нехватке оперативной памяти в рабочем процессе сервера, при перезапуске рабочего процесса и при переключении клиента на другой рабочий процесс. Поэтому если никто «не успел» воспользоваться данными из кэша, то этот ресурс был потрачен зря.

    А самый большой косяк автора — это не рассказать где живут кэши! И что будет при использовании «фичи».

    Чтобы не быть голословным — еще раз перепроверил свои знания практическим примером. Докладываю:

    Повторяемый серверный модуль с вызовом сервера имеет 2 кэша: как на сервере, так и на клиенте!!! Если самому «установить» в закэшированную структуру значение, то оно запишется в кэш только там где его присвоили (на клиенте или на сервере). Т.о. на клиенте и на сервере после такой махинации будем из кэша получать разные значения.

    Reply
  43. unichkin

    Некоторые константы удобнее кэшировать в параметры сеанса.. Вообще у меня в ПовтИсп есть такой метод:

    Функция ЗначениеКонстанты(ИмяКонстанты, ПолучатьДанныеХранилища = Ложь) Экспорт
    ЗначениеКонстанты = Константы[ИмяКонстанты].Получить();
    Если ПолучатьДанныеХранилища И ТипЗнч(ЗначениеКонстанты) = Тип(«ХранилищеЗначения») Тогда
    ЗначениеКонстанты  = ЗначениеКонстанты.Получить();
    КонецЕсли;
    
    Возврат ЗначениеКонстанты;
    
    КонецФункции

    Показать

    Reply
  44. profiprog1c

    (43) «Козырная Монтана»??? Мне что-то смешно. Ладно. Вот «корызная Монтана». Я только что написал обработчик, который 50000 раз читает константу. Все это заняло 14 секунд. Так вот, если вы в реальном программировании используете такие циклы, на 50 тыс. раз, то эти 14 секунд ни на что влиять не будут. Так что советую изучить, что такое «производительность» и что реально требует оптимизации в реальном программировании, а не в Сферическом коне в вакууме, который вы мне тут упорно расписываете.

    Reply
  45. Hobbit_Jedi

    (46) Иногда, 14 секунд — это очень долго.

    К тому же помня, что «Сила мелочей — в их количестве»(С)Народ… очень часто приходится сталкиваться с вроде бы равномерно-тормозящим кодом (где оптимизировать вроде бы нечего), который путем «Сферических» оптимизаций можно ускорить раза в три.

    Если код изначально писать оптимально (с точки зрения Сферического коня в вакууме), то зачастую, как Вы выразились «реальные оптимизации в реальном программировании» — не требуются вообще.

    Хотя да — это мы с Вами уже в Холивар проваливаемся. У каждого свой путь на ниве программирования.

    Reply
  46. pvlunegov

    Батенька, здесь в узких кругах народы привыкли к диссертациям в виде статей, а вы тут статейку написали, вот и ругаются, читать много букоф…

    Мои мысли о применении фичи:

    1. Мониторинг изменения данных в одной функции общего модуля с признаком повторные использование.

    2. В функции получаем нужный список реквизитов нужного объекта метаданных. Храним значения в кешированной таблице.

    3. Функцию получения реквизитов загоняем в цикл и гоняем туда сюда.

    4. При изменении данных в существующих объектах, запускается отдельная процедура по проверке изменений.

    5. Если изменения запрещены по определенному алгоритму — создаем электронное письмо администратору.

    Как работает механизм:

    1. Большие объемы изменения данных.

    2. В момент изменения данных максимальная свобода и производительность системы без дополнительных проверок.

    3. Все проверки в режиме оффлайн.

    4. Проверка изменений осуществляется в оффлайн с помощью кеширования реквизитов и сравнения с существующими в базе.

    5. Если реквизиты изменены не по правилам, то кеш сохраняется в файл на диске, админу 1с приходит письмо с описанием проблемы.

    6. Админ разбирается в правомерности изменения данных.

    7. Если изменение данных запрещено правилами, можно восстановить реквизиты из кеша, который сохранен на диск.

    Плюсы:

    1. Максимальная свобода изменения данных в базе.

    2. Минимум проверок при записи в БД.

    3. Высокая производительность.

    4. Проверки делаются отдельно.

    Минусы.

    1. При большом количестве изменений кеши изменений будут очень большими, нужно место для хранения кешей таблиц.

    Reply
  47. zakiap

    А я использую так:

    Функция Получить_ТаблицаЗначений(_имя) Экспорт
    Возврат Новый ТаблицаЗначений;
    КонецФункции
    

    далее

    КешДокументов = КЭШ.Получить_ТаблицаЗначений(«КешДокументов»);
    ……
    
    Reply
  48. mitia.mackarevich

    (23) Убрал бы из ПР «свой реквизит» и назвал бы его как переделал, ну или отключил галку использовать ВРО в обмене. Это не кэш, это механизм регистрации БСП, где грубо говоря регистрация = ПРО + ВРО

    Reply
  49. Rustig

    (34) использую Допущения во всех задачах у клиентов: пример, цикл в цикле и т.д.

    использую миллион допущений «здесь и сейчас» — потому что знаю бизнес клиента.

    к примеру есть универсальный алгоритм проведения , в котором то там то здесь стоит проверка на валюту — а я знаю, что у клиента бизнес рублевый — удаляю все проверки, везде ставлю курс =1 и т.д.

    ваш пример с зеленым светом — некорректный — вы мыслите узко, кто-то за вас придумал светофор, и вы считаете что так и должно быть — в случае со светофором лучший вариант это интеллектуальный светофор — кнопочный — подходит человек и нажимает кнопку — оповещает о своем намерении перейти дорогу….

    короче,

    1) иногда правильно использовать допущения , и не умножать на 1000 — потому что ваша тыща никогда не случится

    2) иногда правильно не мыслить чужими навязанными шаблонами , а придумать так, чтобы комфортно тебе жилось (заодно и другим)

    за Константу поддерживаю,,механизм в статье путанный , может и годный, но подача материала желает быть лучше

    пытаться создать универсальное решение для разных бизнесов и масштабов — вот яма, в которую попадают разработчики

    Reply
  50. Rustig

    (37) не люблю теории про универсальные решения — каждая задача имеет свое красивое решение, не подходящее для других бизнесов и других масштабов — а вы тут разводите абсолютно идеальное решение неизвестно какой задачи.

    Reply
  51. Rustig

    (43) о какой константе идет речь? пишите конкретно!

    сформулируйте четкую задачу, что нужно проверять при выгрузке в обработчике события?

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

    Reply
  52. redtram

    (49) работает? Если я правильно понял, то мы просто получаем таблицу значений (допустим запросили с клиента, кэш упал в клиента), наполняем ее (наполняется ли она в клиентском кэше? а в серверном?), в дальнейших вызовах получаем только ссылку на эту ТЗ?

    Также вопрос ко всем. Повторное использование общее для всех сеансов (т.е. зависит только от входящих параметров)?

    Reply
  53. Vahnin

    Коллеги, не забывайте, пожалуйста, про стандарты от 1С

    https://its.1c.ru/db/v8std/content/2149184296/hdoc

    Всеми любимое слово «Получить» в именах функций 1С использовать не рекомендует.

    P.S. Не нашел информации, где все-таки хранится кэш (клиента и сервера), в tempdb, в файлике в AppData или еще где. Есть у кого инфа?

    Reply
  54. Vahnin

    Коллеги, не забывайте, пожалуйста, про стандарты от 1С

    https://its.1c.ru/db/v8std/content/2149184296/hdoc

    Всеми любимое слово «Получить» в именах функций 1С использовать не рекомендует (прямо, конечно, это не указано).

    P.S. Не нашел информации, где все-таки хранится кэш (клиента и сервера), в tempdb, в файлике в AppData или еще где. Есть у кого инфа?

    Reply
  55. a.x

    (22) Лучше сделать два метода — первый в обычном модуле (без повторного использования), второй — в модуле с повторным использованием.

    Модуль без повторного использования

    Функция ПолучитьКешируемоеЗначение(Обновить = Ложь) Экспорт
    
    Кеш_ = МодульПовтИсп.ПолучитьКеш();
    
    Если Истина = Обновить Тогда
    Кеш_.Очистить();
    КонецЕсли;
    
    Если Не Кеш_.Свойство(«Значение») Тогда
    // Инициализируем кешируемое значение.
    Кеш_.Вставить(«Значение», 3.1415);
    КонецЕсли;
    
    Возврат Кеш_.Значение;
    
    КонецФункции
    

    Показать

    Модуль с повторным использованием значений (МодульПовтИсп)

    Функция ПолучитьКеш() Экспорт
    
    Кеш_ = Новый Структура;
    
    Возврат Кеш_;
    
    КонецФункции
    

    Показать

    Reply
  56. a.x

    Полезный, с моей точки зрения, вариант использования модуля с повторным использованием — замена магических констант в коде. Например:

    Что было (и это я видел даже в типовых)

    …
    ОбрабатываемаяДата = ОбрабатываемаяДата + 86400;
    …
    

    Добавляем модуль с повторным использованием, назовем его ДемистификацияКонстант.

    Функция ОдниСутки() Экспорт
    
    Возврат 24 * 60 * 60; // Часы, минуты, секунды.
    
    // А ещё лучше вот так.
    ОдниСутки_ = ‘2018-11-22’ — ‘2018-11-21’;
    Возврат ОдниСутки_;
    
    КонецФункции
    

    Показать

    Что стало

    …
    ОбрабатываемаяДата = ОбрабатываемаяДата + ДемистификацияКонстант.ОдниСутки();
    …
    
    Reply
  57. a.x

    (56)

    Не нашел по указанной ссылке запрета на использование слова «Получить» в именах методов.

    Reply
  58. triviumfan

    (9) Почему тогда в БСП такие константы кешируются?

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *