powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Оптимизация работы со строками
18 сообщений из 18, страница 1 из 1
Оптимизация работы со строками
    #32402503
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
г-да Программеры!

Помогите решить такую проблему
Возникает необходимость конкатенации строк в цикле примерно так

Код: plaintext
1.
2.
3.
For i =  1  to  5000  
     str = str & GetID(str) 
Next i 


Это работает ровно 30 секунд...
Нельзя ли как-нибудь ускорить сей процесс?
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402544
boevik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Может проблема в GetID?
Код
Код: plaintext
1.
2.
For i =  1  to  10000  
     str = str &  10000  
Next i 

выполняется за треть секунды
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402580
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
To boevik
А какая у Вас машина?
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402586
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
To boevik
И заодно попробуйте вот так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Dim i As Long
Dim str As String
Dim str2 As String
str2 =  "5000 "

For i =  1  To  10000 
    str = str & str2
    str = str & str2
    str = str & str2
Next i
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402626
boevik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Была у меня проблема с конкатенацией. Начинает тормазить когда размер переходит 70000 символов. Цифра установлена эксперементально.
Выход, разбить на несколько длинных строк.
Конкатенация двух длинных строк происходит мгновенно (мгновенно - в переделах разумного)
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402709
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
К сожалению, я не могу разбить эту операцию на конкатенацию длинных строк,
т.к. необходимо накапливать в переменной значения, выбираемые с помощью процедуры в цикле.
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402793
boevik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Никогда не говори никогда.

Можно накапливать в разные строки и потом их объеденять.
К примеру код:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
Private Sub Command1_Click()
Dim i As Long
Dim s1 As String
Dim t As Single
Dim s() As String

s1 =  "50000 "
t = Timer
ReDim s( 0 )
For i =  0  To  100000 
If Len(s(UBound(s))) <  10000  Then   'длина буфера не более 10,000
    s(UBound(s)) = s(UBound(s)) & s1
Else
    ReDim Preserve s(UBound(s) + 1)
    s(UBound(s)) = s1
End If
Next i
Debug.Print Timer - t; Len(s(0)); UBound(s)

'сбор строк в одну длинную строку
For i =  0  To UBound(s)
    s1 = s1 & s(i)
Next i
Debug.Print Timer - t; Len(s1)
End Sub


Очень интересно поэксперементировать с длинной буфера.
Время изменяется от 2 секунд при длине 10,000 символов до 1.5 минуты при длине 100,000. (А что бы все загнало в одну строку, так результата не дождался даже после нескольких минут ожидания)

Выводы напрашиваются сами
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402893
Hibernate
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
For i =  1  to  5000  
     str = str & GetID(str) 
Next i 


а как объявлена функция GetID ? и изменяется ли в этой функции значение входного параметра str?
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402915
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
to Hibernate
вообще-то должно быть GetID(i) :).
Но дело тут не в функции, т.к. я ее вызов заменял на " & "авава"" - результат тот же.
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32402918
Andy154
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
To boevik

Предложение очень интересное. Пошел пробовать. Спасибо, boevik.
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32403875
Фотография Нуф-нуф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Перед началом конкатенации попробуй загнать в "накопляющую" строку ожидаемое максимальное количество символов, тем самым выделив единожды под нее память, а не каждый раз при очередной канкатенации. Затем загони в нее самое начало строки и уже в цикле добавляй прочие "куски". Сейчас попробовать не могу, но исходя из теории прирост в производительности должен почувствоваться...
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32403882
Фотография Нуф-нуф
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, и еще вместо конкатенации (&) попробуй выполнять сложение (+). Это сработает и тоже даст прирост производительности в случае если будешь складывать строки со строками...
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32405263
Фотография Senin Viktor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в продолжении Нуф-Нуфа
если работать с большой, заранее сформированнной, строкой с помощью оператора MID (не путать с функцией MID) - то рост производительности м.б. в разы.
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #32407457
marvan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если не давать VB самому работать со строками время уменьшается с 3.9 сек до 0.08 сек

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
Private Declare Sub CopyMemory Lib  "kernel32"  Alias  "RtlMoveMemory"  (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Private Declare Sub CopyLng Lib  "kernel32"  Alias  "RtlMoveMemory"  (ByVal pDst As Long, pSrc As Long, Optional ByVal Bytes As Long =  4 )
Private Declare Function SysAllocStringByteLen Lib  "oleaut32.dll"  (ByVal lpstr As Long, ByVal ByteLen As Long) As Long

'Int((1000 * Rnd) + 1) ' возвращает числа от  1  до  1000 

...
    Dim str1 As String
    Dim str2 As String
    Dim L1 As Long
    Dim L2 As Long
    Dim mPtr As Long
...
'Вариант 1 выполняется за 3.9 сек
    str1 = ""
    For i = 0 To 10000
        str2 = Int((1000 * Rnd) + 1)
        str1 = str1 & str2
    Next i
'Вариант  2  выполняется за  0 . 08  сек
...   
    str1 = ""
    L1 =  0 
    L2 =  0 
    Dim a( 0  To  80000 ) As Byte
    For i =  0  To  10000 
        str2 = Int(( 1000  * Rnd) +  1 )
        L2 = LenB(str2)
        CopyMemory a(L1), ByVal StrPtr(str2), L2
        L1 = L1 + L2
    Next i
    str1 = a()
    mPtr = StrPtr(str1) -  4 
    CopyLng mPtr, L1
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Оптимизация работы со строками
    #33120286
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
marvanВариант 2 выполняется за 0.08 сек

А можно это оформить в виде функции? А то у меня вместо нужной строки хрень какая-то получается.
Типа так:
Код: plaintext
1.
2.
3.
Function Concat(Str1 as String, Str2 as String) as String
    'Concat = Str1 & Str2
End Function
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #33120664
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Antonariy marvanВариант 2 выполняется за 0.08 сек

А можно это оформить в виде функции? А то у меня вместо нужной строки хрень какая-то получается.
Типа так:
Код: plaintext
1.
2.
3.
Function Concat(Str1 as String, Str2 as String) as String
    'Concat = Str1 & Str2
End Function


"Это" (конкатенацию пары строк) практически абсолютно бессмысленно оформлять в виде функции.
(Если у тебя проблема с конкретным кодом - лучше опиши, в чем она, чем тратить время на такую функцию.)

Написать функцию эффективней того, что ты сам только что написал почти
нелья. Почти в том смысле, что в pCod-e любая функция будет заведомо
давать проигрыш по сравнению с инлайн-соединением, в компилированном
коде "могут быть варианты", но они заведомо не стоят по достигнутому
результату приложенных услий, и абсолютно не оправдают ожиданий.
Причины этого будут изложены ниже.

"Это" (циклические соединения строк) чаще принято оформлять в виде классов, набирающих строки и отдающих их
"за раз".
Самая короткая, простая, но достаточно эффективная и красивая
своей краткостью реализация из тех, что доводилось видеть - принадлежит
Андрею Митину:
http://am.rusimport.ru/MsAccess/topic.aspx?ID=261

вот тут чуть сложнее
http://www.vbaccelerator.com/home/VB/Code/Techniques/StringBuilder/String_Builder_Class_and_Demonstration_zip_cStringBuilder_cls.asp

Вообще, если полазить по интернету, то с пяток относительно различных реализаций для VB4|5|6 наберется.

Все они (как и приведенный 12 фев 04, 16:47 код от marvan ) так или иначе
используют одни и те же принципы работы со строками, понимание которых
складывается примерно таким набором:

- сложение (очень) коротких строк происходит весьма быстро и, если речь идет о сложении всего нескольких (очень) коротких строк - не о чем заморачиваться и некого обгонять. ("Длинное" и "короткое" чуть ниже слегка,
но не полностью уточнится).

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

Для VB/VBA выделение строк (как и для всех остальных "потребителей в системе", обращающихся к COM за получением строк) производят функции из
OleAut32.dll. В отношении строк - это общесистемное узкое горло. В многозадачном окружении запросы на памать для строк COM отрабатывает последовательно. (Это значит, что если есть несколько VB-Like приложений,
очень активно работающих со строками, то они, являсь прямыми
конкурентами за общий, но последовательно раздаваемый ресурс, только по
одной этой причине вместе отработают гарантированно за большее время
(простаивая в очереди на обслуживание), чем сумма времен их "монопольной
работы".) Строки - это в целом дорого. (Впрочем, как и динамические массивы).
Длинные строки выделяются из общесистемной кучи. В нагруженной "активно-строковой" ситуации, при интенсивном обращении за новыми (все более длинными) строками (и не освобождении ранее занятой памяти) "строковое пространство" (может) быстро дефрагментируется и все заканчивается сообщением об ошибке - "память для строк исчерпана. Каюк."
(И, чем ближе к этому "каюк", тем медленней начинает отзыватся система, аккуратно выискивая - есть ли у нее еще или уже нет, возможность выполнить запрос на выделение памяти. Особенно, когда строко-пожирательных задач в системе оказывается "много".)

Короткие строки (по возможности) выделяются из внутреннего кеша в 64К, размещаемого в недрах OleAut32.dll.
Если там еще осталось место, не занятое другими короткими строками и строки-операнды "уже там", а строка результат способна разместиться в этом оставшемся месте в виде непрерывного диапазона - значит вам настало шчастье и опреация сложения строк выполнится так быстро, как это вообще возможно в COM.
Такое сложение "самооптимально" и по скорости его по существу - "нельзя улучшить".

Из всего вышесказанного выводятся следующие самые общие рекомендации по работе со строками.
- myStr = vbNullString - это вполне приличный тон, когда вам больше не нужно ранее заказанное строковое пространство. На мой взгляд, для коротких это в целом важнее, чем для длинных.
- За выделением длинных строк следует обращаться настолько редко,
насколько это вообще возможно по смыслу конкретной задачи и/или универсальности применения разрабатываемого класса (или функции, содержащей в себе цикл накопления строки). Стандартный способ - запросить (строку) с большим или меньшим запасом и потом "вписывать в запрошенное", а не "складывать".

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

В таких техниках очень эффективно использование функции Join. Похоже, она инспектирует свой массив на длины складываемых
строк, выделяет память для строки-результата за одно обращение и
копирует в результирущую строку строки, составляющие переданный Join массив.

ЗЫ
за многословие - извинения с выражением.
Но зато нажмакался.
:)
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #33120855
marvan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот чем я пользуюсь:

Код: plaintext
1.
\'класс объединения строк clsAppendString\'пример использования \'Dim mStr As New clsAppendString \'For i = 1 To 10000\'    mStr.Add str2\'Next i\'str1 = mStr.StrOption Explicit    Private LenTxt As Long \'реальный размер текста    Private TxtBuf As String  \'буфер    Private LenBuf As Long \'размер буфера    Private PtrBuf As Long \'указатель на буферPrivate Sub Class_Initialize()    LenBuf = 255    LenTxt = 0    TxtBuf = Space(LenBuf)End SubPublic Sub Add(ByRef nStr As String)    Dim LenStr As Long    LenStr = Len(nStr)    If LenStr = 0 Then Exit Sub    If (LenTxt + LenStr) > LenBuf Then        LenBuf = (LenTxt + LenStr) * 2&        TxtBuf = TxtBuf & Space$(LenBuf)    End If    Mid$(TxtBuf, LenTxt + 1&) = nStr    LenTxt = LenTxt + LenStrEnd SubPublic Property Get Str() As String    LenBuf = LenTxt    Str = Left$(TxtBuf, LenTxt)End PropertyPublic Function Cls()    LenBuf = 255    LenTxt = 0    TxtBuf = Space(LenBuf)End Function
Как отформатирован этот код?

- это быстро
- это удобно использовать
- это не содержит опасных API вызовов
...
Рейтинг: 0 / 0
Оптимизация работы со строками
    #33121281
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за исчерпывающий ответ =)
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / Оптимизация работы со строками
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]