Имя: Пароль:
1C
 
Производительность 1С по выделению i-го символа в огромной строке.
0 Гений 1С
 
гуру
11.09.20
12:07
У нас тут с коллегой не из мира 1С возник вопрос по производительности разбора строк.
https://geniy1s.ru/developments-1s/1s-data-exchanges/csv-xml-translation

Дело в том, что я скопировал из интернетов функцию по разбору CSV. Она берет файл в одну строку и перебирает по символьно, то есть использует Сред(Строка, Поз, 1).
Алгоритм работает медленно и я сказал товарищу, что проблема имеенно в том, что 1С постоянно ищет символ с номером Поз.

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

Файлы там большие, думаю, занимают несколько страниц в памяти по 64Кб. Как думаете, поиск в огромной строке по номеру позиции всегда нагружает систему или 1С как-то этот момент кэширует.
1 ДенисЧ
 
11.09.20
12:09
"я отказался."

Ну и кто тут злобный аутодендромутант?
2 acht
 
11.09.20
12:09
(0) > Он предложил написать тестовый замер скорости на поиск, я отказался.
Браво! И приперся делегировать эту задачу на форум.
3 Гений 1С
 
гуру
11.09.20
12:12
(2) ну тут есть любознательные. ;-) Я отказался, потому что думаю, что 1с не умеет кэшировать. Может, кто заморачивался на каких проектах
4 fisher
 
11.09.20
12:12
(0) "или 1С как-то этот момент кэширует"
Какой "момент"?
5 Ботаник Гарден Меран
 
11.09.20
12:15
Есть ЧтениеТекста, читает за раз столько символов, сколько укажешь.
6 fyn
 
11.09.20
12:24
(0) Дед, иди к себе в коммерчески успешный бложег и не отвлекай нормальных людей от работы
7 Вафель
 
11.09.20
12:26
1с работает тормозно со строками
8 Вафель
 
11.09.20
12:27
можно строку в массив разбить
9 H A D G E H O G s
 
11.09.20
12:30
(7) Нет
10 Вафель
 
11.09.20
12:35
значит только сложение тормозит?
11 H A D G E H O G s
 
11.09.20
12:37
(10) Сложение строк тормозит везде, если только нет хитрых вещей типа буфера.
12 H A D G E H O G s
 
11.09.20
12:39
(10) На самом деле нормальный человек натравит замер на этот кусок копра в (0) в академических интересах и потом выкинет его накуй.
13 Гений 1С
 
гуру
11.09.20
12:41
(12) для меня производительность была не критичной. Статью написал позже. не подумал замеры сделать.
14 Вафель
 
11.09.20
12:41
(12) а какой хороший код по разбору csv?
15 Гений 1С
 
гуру
11.09.20
12:44
(14) Ну как минимум использовать построчный разбор, а не тянуть весь файл из одной строки.
16 vit-alx
 
11.09.20
12:44
(14) лучший код это впулить его булкой в скуль и работать уже с курсором. остальное от лукавого
17 Гений 1С
 
гуру
11.09.20
12:44
(16) это надо скуля иметь.
18 Web00001
 
11.09.20
12:47
Когда то очень давно когда начинал писать https://www.1c-cod.ru/ я с дурости сначала взял и прям чуть ли не посимвольно, раскраску кода с ИТС переписал на питоне. То, что отрабатывало за секунды на 1с, на питоне занимало чуть ли не минуты
19 Повелитель
 
11.09.20
12:49
(0) Слушайте, если действительно было бы интересно.
То накодить это не дольше чем тему на форуме создать.
На вскидку там 10-15 строк кода + замер.
20 Гений 1С
 
гуру
11.09.20
12:53
(19) счас, я замерю, так и быть.
21 Гений 1С
 
гуру
11.09.20
12:55
(19) и потом, есть молодые, борзые и дерзские, им только задачу интересную дай - порвут на куски. А я так сказать, мудрый Акелла
22 МихаилМ
 
11.09.20
13:23
(0)
откройте для себя xml преобразования  xslt
http://catalog.mista.ru/public/409356/
23 МихаилМ
 
11.09.20
13:28
+(22) пример не совсем удачный, тк можно избежать строки внутренней . преобразование поддерживает тип valuetable те может вернуть сразу таблицу значений.
24 H A D G E H O G s
 
11.09.20
13:39
(14) Прочитать через ЧтениеФайла с разделителем csv через ПрочитатьСтроку
25 H A D G E H O G s
 
11.09.20
13:46
Даже проще - прочитать через ЧтениеФайла с разделителем ПС в переменную
Переменную разложить в массив подстрок по csv разделителю
26 Вафель
 
11.09.20
13:58
(25) для строк с кавычками так не сработает
27 Вафель
 
11.09.20
14:01
а для csv как в тж, где кавычки 2х типов и переносы строк внутри тем паче
28 Zamkadysh
 
11.09.20
14:08
(0) Строка хранится в памяти как массив символов. При обращении по номеру символа, ни какого "поиска", конечно, нет - сложность там O(1) (и не как в хеш мапе - при определенной фазе луны, а всегда - это ведь просто взятие куска памяти по смещению).
Если просто посимвольно перебирать строку - всё время уйдёт в выделение и освобождение памяти (ведь каждый вызов Сред должен выделить новую строку, а потом когда она станет не нужна - освободить).
29 polosov
 
11.09.20
14:20
(28) Зачем выделать/освобождать, если можно пользоваться одной символьной переменной?
Java головного мозга?
30 Asmody
 
11.09.20
14:20
(0) вопрос 1: это нужно было 1 раз, изредка или всегда?
31 fisher
 
11.09.20
14:27
(28) Сложность и быстродействие - не одно и тоже. Можно и при константной сложности иметь неважное быстродействие. Скорость интерпретации как таковой в 1С тоже играет роль ибо вполне существенна. Сплошь и рядом в 1С можно выиграть на банальном уменьшении количестве операций интерпретатора при использовании более высокой сложности, но задействовав библиотечные функции.
32 Zamkadysh
 
11.09.20
14:27
(29) Символьного типа во встроенном языке 8ки нет, а даже если бы и был, в данном случае это не изменило бы ничего.
Строки во встроенном языке (как и в подавляющем большинстве современных ЯП) изменять нельзя.
Переменная-то одна, но объект каждый раз заново выделяется.
(0) Посмотрел код. В качестве некоторой оптимизации - можно в теле цикла вместо СтрокаФайла = Новый Массив, вызывать СтрокаФайла.Очистить().
33 Zamkadysh
 
11.09.20
14:30
(31) В (0) ведь не какой абстрактный вопрос, а вполне конкретное предположение:
>проблема имеенно в том, что 1С постоянно ищет символ с номером Поз
Именно его я пытался прокомментировать.
34 Гений 1С
 
гуру
11.09.20
14:34
Короче, сделал замер разбора CSV 76 Гб, операции сравнения строк тоже затратные, не только выделение символа:
https://www.evernote.com/l/Act81qhAMvtHeKEf4KgHo0cYLKE26Iy6Nik/
35 polosov
 
11.09.20
14:40
(32) С чего ты взял, что в 1С строки имеют объектную природу?
36 Ботаник Гарден Меран
 
11.09.20
14:43
Еще можно небольшие циклы в одну строку написать. На таком количестве циклов должно иметь эффект.
37 Asmody
 
11.09.20
14:44
(36) да ладно!
38 Zamkadysh
 
11.09.20
14:45
(35) Все значения во встроенном языке независимо от типа всегда размещаются в "кучу" (heap'е). Других вариантов просто не предусмотрено.
P.S. Я ничего не говорил про "объектную" природу - это уже какое-то семантическое качество, в этой же ветке вроде производительность обсуждается.
P.P.S. "С чего взял" - "сорока на хвосте принесла".
39 Zamkadysh
 
11.09.20
14:46
(3?) Эффект точно будет - отладчик и замер производительности работать перестанут ;)
40 Garykom
 
гуру
11.09.20
14:47
(25) Гм ты реально не в курсе про особенности вполне валидных CSV ?
41 Asmody
 
11.09.20
14:48
(34) это ты 76 гб в одну строку запихал?! Гений чо!
42 Leonardo1c
 
11.09.20
14:49
А файл читать построчно что не захотел?
43 Гений 1С
 
гуру
11.09.20
14:59
(42) код не мой. Проще так оставить, чем перепиисывать
44 Повелитель
 
11.09.20
15:03
(34) По замеру не понятно, кэширует или нет?
45 mistеr
 
11.09.20
15:17
(28) >При обращении по номеру символа, ни какого "поиска", конечно, нет - сложность там O(1)

Не все так просто. Все строки в 1С это Юникод, в кодировке UTF-8. Это кодировка с переменной шириной символа. Он может занимать и 2, и 3, и 4 байта, а в самых экзотических случаях и больше. Поэтому просто взять смещение в памяти не получится, это именно поиск, с самого начала строки. Этот код, конечно, оптимизирован, но время занимает.

В других языках, более богатых типами, можно хранить строки в кодировке с фиксированной шириной символа, например двухбайтовой. Тогда выделение подстроки будет действительно выполняться за константное время. В 1С такой возможности нет.

Поэтому в подобных задачах файлы лучше считывать построчно и искать/парсить в пределах строки.
46 Гений 1С
 
гуру
11.09.20
15:21
(44) Такие вот в 1с замеры
47 hhhh
 
11.09.20
15:41
(46) пробуй новую функцию СтрРазделить. Она работает в сотни раз быстрее, чем старые строковые функции. То есть читаешь файл полностью и разбиваешь на массив строк - занимает несколько миллисекунд.
48 acht
 
11.09.20
15:52
(45) Там внутри двухбайтовый char16_t, т-щ программист.
Они про это рассказывали когда описывали процесс перехода на C++17

Но выдумать проще и притягательней, согласен.
49 mistеr
 
11.09.20
15:54
(48) Ссылка есть?
А в доке пишут utf-8.
50 acht
 
11.09.20
15:56
(49) В доке на что?
51 mistеr
 
11.09.20
16:00
(50) Ну не в доке, в одной из книжек по 1С видел. Про архитектуру что-то.

А про двухбайтовые строки очень интересно подтверждение, если есть.
52 acht
 
11.09.20
16:00
Ты попробуй, например, вывести СтрДлина(Символ(65536)), весьма удивишься
53 mistеr
 
11.09.20
16:00
(51) "по 1С" читать как "от 1С"
54 acht
 
11.09.20
16:01
Вот тут, например, они немного рассказывают как от STLPort уходили
https://habr.com/ru/company/1c/blog/429678/
55 acht
 
11.09.20
16:02
Теперь ты давай свою "одну из книжек от 1С про архитектуру что-то."
56 Serginio1
 
11.09.20
16:04
Попробуй этот http://catalog.mista.ru/1c/articles/371887/
Он использует Найти
57 Zamkadysh
 
11.09.20
16:09
(45) >Не все так просто.
Да нет, всё именно так просто.

>Все строки в 1С это Юникод
Это да

>в кодировке UTF-8.
А вот это нет.
UTF-8 используется только в качестве внешней кодировки по умолчанию.
В памяти всё в UTF-16.
Как в java.
Т.е. символ это всегда 2 байта.
В unicode символ это совсем не всегда 2 байта.
Но и "символы" во встроенном языке это совсем не всегда символы - можно получить вместо символы половину суррогатной пары.
Например, если сделать строку из одного символа эмозди и получить через Сред первый символ - вместо символа получится нечитаемый мусор (а длина строки будет 2).
58 mistеr
 
11.09.20
16:15
(54) Спасибо. Значит UTF-16.

>к весне 2017 (версия 8.3.11 1С:Предприятия) миграция была завершена

Книжка, в которой я видел utf-8, скорее всего более ранняя.
59 mistеr
 
11.09.20
16:17
(57) UTF-16 это тоже кодировка с переменной длиной, строго говоря.

>если сделать строку из одного символа эмозди и получить через Сред первый символ

Проверял?
60 acht
 
11.09.20
16:24
(58) А по состоянию на "более раннюю книжку" у них был wchar_t. Который в Windows 2 байта, а в Linux 4. Ссылка та же.
61 acht
 
11.09.20
16:25
(60) А откуда ты теперь UTF-16 нафантазировал?
62 acht
 
11.09.20
16:25
(61) к (59)
63 Zamkadysh
 
11.09.20
16:25
(58) >Книжка, в которой я видел utf-8, скорее всего более ранняя.
В stlport'е тоже, конечно utf-8 не используется.
Стандартная плюсовая строка вообще ни как не может быть из символов разного размера.
(59) >Проверял?
Нет.
Как и многие другие вещи.
Это просто теоретическое построение на основе того что:
* все эмодзи - это суррогатные пары
* 8ка использует 16битные "символы" (т.е. строго говоря это могут быть и не символы, а только их части - как и в java, но почти всем на это наплевать потому что в жизни суроггатные пары встречаются редко)
* 16 битный символ содержит половину суррогатной пары
Какой смысл после этого проверять что первый "символ" от эмодзи будет содержать половину суррогатной пары?
64 Zamkadysh
 
11.09.20
16:27
(62) А есть (более менее реалистичные) варианты что ещё хранить в 2байтовом символе?
65 acht
 
11.09.20
16:29
(64) UCS-2 например, фиксированная ширина.
UTF, они ж по определению переменной ширины, чиселки после - это всего разрядность одной части
66 Вафель
 
11.09.20
16:36
но получение символа по номеру в строке  должно же учитывать переменность длины
67 Zamkadysh
 
11.09.20
16:36
(65) Но там просто нет символов за пределами 65к вообще.
В 8ке же они есть (на счёт поддержки именно эмодзи на самом деле есть определенные сомнения, а проверять лень).
68 mistеr
 
11.09.20
16:37
69 NorthWind
 
11.09.20
16:37
(67) держит, я пробовал.
70 NorthWind
 
11.09.20
16:39
71 Garykom
 
гуру
11.09.20
16:40
Для извращенцев.
В 1С встроен движок JavaScript внутри ПолеHTML, так что закидываем туда CSV и вперед...
72 Zamkadysh
 
11.09.20
16:40
(66) В каком-то лучшем из миров - наверное.
Но на практике, не учитывает.
В java метод строки charAt тоже может спокойно вернуть половину суррогатной пары (собственно ему больше нечего возвращать, ведь char в java 16 битный - "целый" символ туда может просто не поместиться).
Про C# не в курсе, но что-то мне подсказывает что и там не лучше.
Лучше будет только если сделать символ 32битным (или правда сделать получение символа по индексы "поиском" - т.е. сразу сломать в смысле производительности кучу алгоритмов).
73 Вафель
 
11.09.20
16:40
(72) а в 1с? ктонибуль проверял?
накидай код посмотрим
74 acht
 
11.09.20
16:44
(70) Ну, собственно в твоем куске кода оттуда:

ПолеВвода1 = Символ (55357) + Символ (56832);// D83D и DE00

И есть ответ
75 acht
 
11.09.20
16:44
(68) О, точно, спасибо
76 Zamkadysh
 
11.09.20
16:47
(73) Мне не удалось вставить
😁
Ни в исходный текст модуля (в конфигураторе), ни в поле ввода.
Я думаю 8ка просто их не поддерживает ;(
77 Вафель
 
11.09.20
16:54
через буфер нельзя но файл открывается
78 Ненавижу 1С
 
гуру
11.09.20
17:15
(0) на мисте ты обещал, что в твоем уютном бложике https://geniy1s.ru/ будут (почти) ежедневно статьи появляться. Не смог? Или биржевые спекуляции затянули?
79 VladZ
 
11.09.20
17:26
Реклама блога Гения1С.
80 Zamkadysh
 
11.09.20
17:43
(77) Попробовал через файл (засунул его в макет, дальше прочитал через ЧтениеТекста), результат вполне ожидаем:
СтрДлина(Строка) = 2
Сред(Строка, 1, 1) = "?"
Сред(Строка, 2, 1) = "?"
Сред(Строка, 1, 2) = "😁"

? стал уже после копирования через clipboard исходно там визуально был пробел.
81 ДенисЧ
 
11.09.20
17:51
(80) А если код символа посмотреть?
82 Zamkadysh
 
11.09.20
18:00
(81) КодСимвола(Строка, 1) = 55 357
КодСимвола(Строка, 2) = 56 833
83 NorthWind
 
11.09.20
22:43
(76) слушай, ну я вставлял и работало. См. (70), (74). Они в стандартных шрифтах не особо красивые рожицы, но есть. Их видно, и они именно такие как должны быть.
84 NorthWind
 
11.09.20
22:49
(45) в винде стандарт USC-2, а не UTF-8.
85 NorthWind
 
11.09.20
22:56
(65) там не вполне так. UCS-2 и UTF-16 по сути одно и то же, только первый вариант более устаревший и там что-то не поддерживается. А переменная длина символа там, кажется, может быть у всего, кроме самой широкой. Другой вопрос что это не всегда используется.
86 Конструктор1С
 
12.09.20
06:56
(13) "для меня производительность была не критичной"

Под таким девизом проходят многие говноподелки. И ладно если бы речь шла об оптимизации, в ряде случаев до нормальной производительности "руку протянуть": при написании запроса попадать в индексы и использовать подходящие средства платформы. Например, в 1с XML можно читать и записывать разными средствами, но часто использую те, которые более привычны
87 Конструктор1С
 
12.09.20
07:19
(0) ой ё... Нафига я скачал этот говнокод? Чувак, у тебя просто талант писать дерьмище

Как раз в тему, тут недавно был разговор про говнокод и его последствия. А это прям наглядное пособие. Элементарный функционал, но всё так сделано через одно место... Т.е. если такая поделка встретится где-то в проде, то чтобы её переделать потребуется времени больше, чем заново написать такое же с нуля
88 dangerouscoder
 
12.09.20
07:37
(87) варить лохам найденный в гугл говнокод надо тоже уметь..
89 dangerouscoder
 
12.09.20
07:38
(88) *впарить
90 Zamkadysh
 
12.09.20
08:33
(83) Ну а я вставлял и не работало:
* предприятие 8.3.18 (на других не пробовал, может и правда сломали)
* Window 10
* копировал из notepad++
* в веб клиенте ожидаемо работает (но это явно заслуга браузера)
* шрифты тут не причем, если из файла прочитать и вставить в поле ввода - отображается ведь
91 NorthWind
 
12.09.20
15:09
(90) это была 8.3.12, обычная форма, на форме поле ввода и в него кодом то что в (74). Запускаешь форму - и в поле ввода мордочки. Windows 10.
92 mistеr
 
12.09.20
18:17
(91) Выводит строку на экран Windows 10, тут много умк не нужно. А вот функцию Сред() выполняет уже 1С. :)
93 Гений 1С
 
гуру
12.09.20
20:05
(79) да ладно тебе, тут больше кипежа по теме поста, чем той рекламы.
94 Гений 1С
 
гуру
22.09.20
20:09
Кстати, все же поправил код разбора CSV на построчность, получилось так:

&НаКлиенте
Функция ПрочитатьCSV(Знач ТД, Разделитель, КоличествоКолонок) Экспорт
    //http://chel1c.ru/импорт-из-csv-в-1с/
    //ТД - текстовый документ
    
    Результат = Новый Массив; // массив строк
    
    Скобка=ЛОЖЬ;
    Начало=1;
    Колонка=0;
    СтрокаФайла=новый Массив; // массив колонок в строке
    ТекЗн = "";
    
    ВсегоСтрок = ТД.КоличествоСтрок();
    Для НомерСтроки = 1 ПО ВсегоСтрок Цикл
        ТекСтрока = ТД.ПолучитьСтроку(НомерСтроки) + Символы.ПС; //Имитируем перевод строки в конце строки
        ДлинаСтроки = СтрДлина(ТекСтрока);
        для Позиция = 1 по ДлинаСтроки Цикл // обходим файл посимвольно
            
            Символ = Сред(ТекСтрока, Позиция, 1);
            
            //если встречается кавычка, фиксируем ее открытие, прекращаем итерацию и продолжаем цикл.
            Если Символ="""" И Скобка=Ложь Тогда
                Скобка=Истина;
                Продолжить;
                //Если встречается закрывающаяся кавычка, фиксируем ее закрытие и тоже продолжаем цикл
            ИначеЕсли Символ="""" И Скобка=Истина ТОгда
                Скобка=Ложь;
                Продолжить;
            КонецЕсли;
            
            //Если встречается разделитель или перенос строки вне кавычек,
            //вносим информацию в массив
            Если (Символ=Разделитель ИЛИ Символ=Символы.ПС) И Скобка=Ложь Тогда
                Конец=Позиция;
                Колонка=Колонка+1;
                
                //Получаем текущий элемент
                ТекЗн = СокрЛП(Сред(ТекСтрока, Начало, Конец-Начало));
                Если Лев(ТекЗн, 1) = """" Тогда
                    ТекЗн = Сред(ТекЗн, 2);
                КонецЕсли;
                Если Прав(ТекЗн, 1) = """" Тогда
                    ТекЗн = Сред(ТекЗн, 1, СтрДлина(ТекЗн) - 1);
                КонецЕсли;
                
                СтрокаФайла.Добавить(ТекЗн);
                
                //Если набралось количество колонок, равное их количеству в шапке, записываем всю строку
                //в массив и переходим к следующей
                Если Колонка = КоличествоКолонок ИЛИ Символ=Символы.ПС Тогда
                    
                    Результат.Добавить(СтрокаФайла);
                    СтрокаФайла=Новый Массив;
                    
                    Колонка=0;
                КонецЕсли;
                
                ТекЗн = ""; //Сбрасываем ТекЗн
                Начало = Позиция + 1;
                
            КонецЕсли;
        КонецЦикла;
        
        ТекЗн = ТекЗн + Сред(ТекСтрока, Начало); //До конца строки
        Начало = 1; //Начало с новой строки...
    КонецЦикла;
    //Удаляем шапку таблицы из массива строк
    //Результат.Удалить(0);
    Возврат Результат;
    
КонецФункции
95 Ненавижу 1С
 
гуру
22.09.20
20:13
(94) жестко

Если Символ="""" И Скобка=Ложь Тогда

                Скобка=Истина;

                Продолжить;

                //Если встречается закрывающаяся кавычка, фиксируем ее закрытие и тоже продолжаем цикл

            ИначеЕсли Символ="""" И Скобка=Истина ТОгда

                Скобка=Ложь;

                Продолжить;

            КонецЕсли;
96 Гений 1С
 
гуру
22.09.20
20:38
(95) код не мой
97 H A D G E H O G s
 
22.09.20
20:41
Сергей пытается в оптимальность
https://coub.com/view/2jbxaw
98 dangerouscoder
 
22.09.20
20:54
(96) Скобка =?(Символ="""" ,НЕ Скобка,Скобка)
99 Vakhrin
 
22.09.20
21:04
(98) ошибка )

Если Символ="""" Тогда Скобка = НЕ Скобка; Продолжить; КонецЕсли;