|
Производительность 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
|
||||
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
|
(61) Из той же статьи, https://habr.com/ru/company/1c/blog/429678/#comment_19365358
|
|||
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) ошибка )
Если Символ="""" Тогда Скобка = НЕ Скобка; Продолжить; КонецЕсли; |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |