Вход | Регистрация
 

Производительность 1С по выделению i-го символа в огромной строке.

Производительность 1С по выделению i-го символа в огромной строке.
Я
   Гений 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
"я отказался."

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

                Продолжить;

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


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

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

                Продолжить;

            КонецЕсли;
   Гений 1С
 
96 - 22.09.20 - 20:38
(95) код не мой
   H A D G E H O G s
 
97 - 22.09.20 - 20:41
Сергей пытается в оптимальность
https://coub.com/view/2jbxaw


Список тем форума
Рекламное место пустует  Рекламное место пустует
ВНИМАНИЕ! Если вы потеряли окно ввода сообщения, нажмите Ctrl-F5 или Ctrl-R или кнопку "Обновить" в браузере.