purebasic.info

PureBasic forum
Текущее время: Ср ноя 21, 2018 9:49 pm

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 60 ]  На страницу Пред.  1, 2, 3, 4  След.
Автор Сообщение
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Вт окт 02, 2018 8:21 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Вт апр 14, 2009 7:22 pm
Сообщений: 362
Благодарил (а): 1 раз.
Поблагодарили: 13 раз.
Пункты репутации: 0
jobless писал(а):
Но содержимое гаджетов, это же "копеешные" размеры, что тут ускорять?
Я думал что то в потоке и большие объёмы.
Т.е. можно представить приблизительно порядок размеров результата и количество фрагментов для сборки?
Самое узкое место в данном случае это не экономить память не наращивать буфер по каждому чиху а найти компромиссный размер для первоначального захвата и последующих.
И писать соответственно с вычислением и запоминанием следующего свободного байта и если зачем то нужна будет обратная процедура, то хранить таблицу указателей и длинны фрагментов, при нынешних размерах памяти это даже не копейки а доли копеек, как мне кажется.

А так то можно ещё конкретней задачу?

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

Примитивнейший пример иллюстрирующий узкое место
Код:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
EnableExplicit
Define SS.s = "ЁЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮёйцукенгшщзхъфывапролджэячсмитьбю№" +
              "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm" +
              "1234567890+-=/<>" +
              "(){}[]_|" +
              ".,?!:;'~`" +
              "@#$%^&*" +
              ~"\\\""
Define SS1.s= ""
Define SS2.s= ""
Define *pSS
Define SsLc = Len(SS)
Define LnS  = 0
Define SumL = 0
Define i    = 0
Define j    = 0
 
Define A    = 1000
 
Define ST.q
 
Dim ArrStr.s(A)
Dim ArrLS.w(A)
;Формируем массив строк случайной длинны со случайным заполнением печатными символами
For i = 0 To A-1
 LnS = Random(SsLc,1)
 ArrStr(i) = ""
 ArrLS(i)  = LnS
 SumL + Lns
 For j = 1 To LnS
   ArrStr(i) + Mid(SS,Random(Lns,1),1)
 Next
Next
;------------------------------------------------------------------------
ST.q = ElapsedMilliseconds()
For i = 0 To A-1
 SS1 + ArrStr(i)
Next
Debug "Простейшая конкатенация"
Debug ElapsedMilliseconds() - ST
;------------------------------------------------------------------------
ST.q = ElapsedMilliseconds()
SS2 = Space(SumL)
*pSS = @SS2
For i = 0 To A-1
 CopyMemory(@ArrStr(i), *pSS, ArrLS(i)*2) : *pSS+ArrLS(i)*2
Next
Debug "Где то в процессе работы мы хранили длинны строк и сумму их"
Debug ElapsedMilliseconds() - ST
If SS1 = SS2 : Debug "ok" : EndIf
;------------------------------------------------------------------------
ST.q = ElapsedMilliseconds()
SumL = 0
For i = 0 To A-1
 LnS = Len(ArrStr(i))
 SumL + LnS
Next  
SS2 = Space(SumL)
*pSS = @SS2
For i = 0 To A-1
 CopyMemory(@ArrStr(i), *pSS, ArrLS(i)*2) : *pSS+(ArrLS(i)*2)
Next
Debug "Раньше мы не имели инфы о длиннах и по считали перед конкатинацией"
Debug ElapsedMilliseconds() - ST
If SS1 = SS2 : Debug "ok" : EndIf


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


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Вт окт 02, 2018 11:50 pm 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
jobless как изменить это ~"\\\"" на пурике 5,21 это непонимает.
Собственно прога пока загадка, можно в двух словах узнать о ней.

_________________
искатель истины


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Ср окт 03, 2018 3:38 am 
Не в сети
профессор

Зарегистрирован: Пн июл 22, 2013 11:00 pm
Сообщений: 656
Благодарил (а): 2 раз.
Поблагодарили: 34 раз.
Пункты репутации: 9
balex1978 писал(а):
Цитата:
выделять буфер для строки кроме stroka=LSet(stroka,rashetindexa,"")

К слову, я так и непонял как это оно выделяет память под строку.
У пурика это кажется кратно 16 байтам включая ноль в конце и если длинна превышается то наверное все перетасовуется в памяти чтоб освободить для нужного размера.
Но тут строка дает ноль и где ты с ней работаеш, откуда знаеш что выделена, мож не выделена.
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
stroka$="5"
rashetindexa=10
stroka$=LSet(stroka$,rashetindexa,""); просто пустые кавычки это ноль байт
Debug Len (stroka$)
; так например выделяется
 
stroka$="5"
rashetindexa=10
stroka$=LSet(stroka$,rashetindexa," ")
Debug Len (stroka$)
;но это равносильно этому: правда я увеличил с 10 до 200
stroka$=Space(200)
Debug Len (stroka$)
;а дальше это просто изврат какойто который неимеет смысла
; и уже исходя из надобности в эту строку соваеш свою или склеиваеш две
;в результате получается длинна(и буфера тож) которая заканчивается нулем.
 
;буфер размером в stroka$=Space(200) будет существовать пока ты в него невпишеш
; таким пособом stroka$="123" после этого он обрежется до 6 байт в уникоде +1 для ноля с ограничением кратности до 16 байт
; я незнаю как раобтает при этом pokeS() сокращает ли буфер или нет
; но проще для этого использовать алокейтмемори()



К слову так работает медленно всегда: c$=a$+b$

Поэтому я давал код с самоперемещаемым(масив через реДим) и "неперемещаемым" в кавычках буфером аллокатеМемори().

пример строкового буфера под АПИ функцию
Код:
1
2
Path.s=Space(501)
  GetWindowsDirectory_(@Path,500)


после заполнения мне неизвестно буфер остается в 501 или меньше.

адрес строки может менятся, причем пурик сам понимает чего вы хотите сделать и заранее выделяет побольше буфер, жесть.
Код:
1
2
3
4
5
6
a$="1234567890123456789"
Debug @a$
For i=0 To 10
a$=a$+"1234567890123456789"
Debug @a$
Next

Вот результат
3940008
3956504
...
3956504
вот на тыщу строк
3940008
3956504 0-ноль это номер строки в цикле
...
3956504 542 вот бац сменил его адрес
32932000 543
...
32932000 855 вот опять
3940064 856
...
3940064 1000
так что и в пурике без перемещений даже одной переменной необходится.

Вобщем так
Код:
1
2
3
4
5
6
7
8
9
 
Global stroka.s=#NULL$
stroka$=#NULL$
stroka$="5"
rashetindexa=10
stroka$=LSet(stroka$,rashetindexa,"00000"); просто пустые кавычки это ноль байт
Debug stroka$
Debug Len(stroka$)
 


Видишь как работает? вопервых не трогает изначальные данные("5")
делает следующее тупо пропускает первый символ и добавляет другие 9 нулей так как указано общее число символов,это будет равно расширению stroka$+space(9)
поэтому ,rashetindexa=(переменная+увеличенный размер)= space(фиксированный размер увеличения)
но когда делаешь LSet(stroka$,rashetindexa,"") с пустыми кавычками то строка в памяти тоже расширяется только заполняет следующие значения #NULL$(нулями)
поэтому Len(stroka$) у тебя и показывает 1 символ так как считает до 0(конец строки)
поэтому и не происходит у меня в примере переполнения памяти и вылета проги. :D
PS: про массив тоже думал надо подумать. :roll:


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Ср окт 03, 2018 4:33 am 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Вт апр 14, 2009 7:22 pm
Сообщений: 362
Благодарил (а): 1 раз.
Поблагодарили: 13 раз.
Пункты репутации: 0
balex1978 писал(а):
jobless как изменить это ~"\\\"" на пурике 5,21 это непонимает.
Собственно прога пока загадка, можно в двух словах узнать о ней.

выбросить совсем или
Код:
1
2
3
 
Debug Asc(~"\\")
Debug Asc(~"\"")


92
34
т.е. заменить на chr(92)+chr(34) ;
Для меня загадка как раз в том, что есть загадка :)
Что бы не ускорять "сферического коня в вакууме", формируем тестовый массив из N(у меня там кажется A, соответственно меняем в процессе экспериментов и смотрим цифры) строк случайной длинны со случайным заполнением символами из видимых на клавиатуре. Можно конечно и не заполнять таким разнообразием, на дальнейшие цифры это не по влияет, т.е. одним каким то символом строка UTF16LE заполнена или разными не важно, главное какой она длины.
В процессе формирования для последующего использования запоминаем длины строк в параллельном массиве и сумму их, предполагая что в реальной жизни у нас такая возможность тоже будет.
А затем три варианта:
Конкатенация "в лоб" через + + + ...
Сборка строки используя накопленную инфу о длинах и её сумме
И сборка с предварительным подсчётом длин и суммы если в реальной жизни в процессе накопления информации у нас такой возможности вдруг не было.
На моём холодном целероне J1800 W10x64 PB562x64 получаем
----------------------------------------------------------------------------------------------
Строк: 1000
Простейшая конкатенация
334
Где то в процессе работы мы хранили длинны строк и сумму их
1
ok
Раньше мы не имели инфы о длиннах и по считали перед конкатинацией
1
ok

----------------------------------------------------------------------------------------------
Строк: 10000
Простейшая конкатенация
29788
Где то в процессе работы мы хранили длинны строк и сумму их
9
ok
Раньше мы не имели инфы о длиннах и по считали перед конкатинацией
12
ok
----------------------------------------------------------------------------------------------
Что нагляднейшим образом показывает, что дело не в реализации, мой код в этом примере примитивнейший до боли,
дело в принципе, имеем мы инфу о размерах фрагментов и используем её или думаем, что процессор и компилятор волшебники и без нас сами всё сделает красиво.
p.s. Думаю сомнений нет в том, что если будет поставлена действительно реальная конкретная задача, код можно вылизать и добиться ещё более серьёзной разницы в цифрах.
p.p.s. Ещё примечание. Современные размеры памяти и скорости совсем расслабили народ. Знать размер результата перед конкатенацией логично уже только потому, что это гарантирует понимание при попытке выделить память, стоит ли начинать, есть ли место где это всё должно собраться. :mrgreen:


Последний раз редактировалось jobless Ср окт 03, 2018 4:54 pm, всего редактировалось 1 раз.

Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Ср окт 03, 2018 11:46 am 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
Сергейчик писал(а):
Код:
1
2
3
4
5
rashetindexa=10
stroka$=LSet(stroka$,rashetindexa,"00000"); просто пустые кавычки это ноль байт
Debug stroka$
Debug Len(stroka$)
 


Видишь как работает?
...
но когда делаешь LSet(stroka$,rashetindexa,"") с пустыми кавычками то строка в памяти тоже расширяется только заполняет следующие значения #NULL$(нулями)
PS: про массив тоже думал надо подумать. :roll:


Оригинально, добавить в конец LSet както недодумывался.
всеодно вопрос остается как узнать, что оно действительно выделено при пустых кавычках.
Прога конечно невылетает, но где гарантия что Фред код непоменяет.
Просто я сделал такой код и невылетела прога это приятно, но выделив 100 метров прога сожрала 410 метров :shock: :shock: :shock: :shock: ,
помоему этоникуда негодится, конечно, наврядли текстовые файлики имеют такие размерчики, обычно не более 10 метров, но сожрать в 4 раза больше это экономным неназвать :?
Код:
1
2
3
4
5
6
7
8
9
10
stroka$="ASDF"
rashetindexa=100000000
stroka$=LSet(stroka$,rashetindexa,""); просто пустые кавычки это ноль байт
Debug stroka$
Debug Len(stroka$)
PokeS(@stroka$,Space(rashetindexa/100))
a$="fghv"
s$="jhfb"
; ASDF111111 поэтому LSet(stroka$,rashetindexa,"1") равносильно
; 10



вот тоже самое выделение 100 метров без разрушения даных, прога хавает 116 метров :) :P
Код:
1
2
3
4
5
6
Dim a.b(20)
ln=PokeS(@a.b(0),"Sos")
Debug PeekS(@a.b(0))
ReDim a.b(100000000); выделяем 100 метров
Debug PeekS(@a.b(0))
Delay(2000)



С масивами, их легко просматривать чем угодно и хоть в дебугере с розбросаных мест памяти, чего невозможно стандартным просмотрщиком, либо вызывать просмотрщик и кудато в блокнот писать результаты.
Например бинарный масив создаем a.b(100)
а так просматриваем содержимое
peekB(@a.b(29)) или так peekB(@a.b(0)+29)
но зачем морочится если можно так Debug a.b(29)
ну а если масив в несколько метров и даные разброснаы везде и нужно десяток
ячеек контролировать, то этот метод легкий
Debug a.b(29):Debug a.b(1123):Debug a.b(55621)... вместо
ShowMemoryViewer(@MEM+29,200):CallDebugger
ShowMemoryViewer(@MEM+1123,200):CallDebugger
ShowMemoryViewer(@MEM+55621,200):CallDebugger
.... и еще куча и еще каждый раз смотреть

_________________
искатель истины


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Ср окт 03, 2018 11:52 pm 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
jobless понятно, я до вашего коментария сидел до часу ночи розшифровывал и переделывал чтоб понять, что это за код и даже пришлось полезть в википедию, чтобы узнать что значит загадочное слова - конкатенация, сильное слово.
После упростил до мизера и ввел варианты добавления или копирования, както так.

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

Код:
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
34
35
36
37
38
39
40
a=200000;строчек
Dim ArrStr.s(A);масив строк разной длинны
Dim ArrLS.w(A);масив длинны
 
t= ElapsedMilliseconds()
; создание масива строк
;ваш код можно заменить таким(я долго пытался понять что это такое)
For i = 0 To A-1
    ArrStr(i) = ")(%?(*№"+Str(i)+"_)*%)!*?:;)!:)(%?№******";""
    LnS = Len(ArrStr(i) )
    ArrLS(i)  = LnS
    SumL + Lns
Next
; ; или таким
; For i = 0 To A-1
;     LnS = Random(50,1);длинна строки
;     ArrLS(i)  = LnS
;     SumL + Lns
;     For j = 1 To LnS; создаем строку из букавок
;         ArrStr(i) + Chr(Random(126,52))
;     Next
; ;ArrStr(i) +"*****"
; Next
Debug ElapsedMilliseconds()-t
 
t= ElapsedMilliseconds()
SS2$ = Space(SumL)
*pSS = @SS2$
For i = 0 To a-1
    LN=Len(ArrStr(i)); закоментировать если розкоментировать следующую строку
;ниже идут три варианта добавления в строчку
    ;CopyMemory(@ArrStr(i), *pSS, ArrLS(i)*2) :*pSS+ArrLS(i)*2
    ;CopyMemory(@ArrStr(i), *pSS, LN*2)
    PokeS(*pSS,ArrStr(i),LN*2)
    *pSS+LN*2
Next
Debug ElapsedMilliseconds()-t
 
;Debug SS2$;выводим содержимое строки, когда большая лучше ненужно
 


_________________
искатель истины


Вернуться наверх
 Профиль  
 
СообщениеДобавлено: Чт окт 04, 2018 6:15 am 
Не в сети
профессор

Зарегистрирован: Пн июл 22, 2013 11:00 pm
Сообщений: 656
Благодарил (а): 2 раз.
Поблагодарили: 34 раз.
Пункты репутации: 9
balex1978 писал(а):
jobless понятно, я до вашего коментария сидел до часу ночи розшифровывал и переделывал чтоб понять, что это за код и даже пришлось полезть в википедию, чтобы узнать что значит загадочное слова - конкатенация, сильное слово.
После упростил до мизера и ввел варианты добавления или копирования, както так.

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

Код:
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
34
35
36
37
38
39
40
a=200000;строчек
Dim ArrStr.s(A);масив строк разной длинны
Dim ArrLS.w(A);масив длинны
 
t= ElapsedMilliseconds()
; создание масива строк
;ваш код можно заменить таким(я долго пытался понять что это такое)
For i = 0 To A-1
    ArrStr(i) = ")(%?(*№"+Str(i)+"_)*%)!*?:;)!:)(%?№******";""
    LnS = Len(ArrStr(i) )
    ArrLS(i)  = LnS
    SumL + Lns
Next
; ; или таким
; For i = 0 To A-1
;     LnS = Random(50,1);длинна строки
;     ArrLS(i)  = LnS
;     SumL + Lns
;     For j = 1 To LnS; создаем строку из букавок
;         ArrStr(i) + Chr(Random(126,52))
;     Next
; ;ArrStr(i) +"*****"
; Next
Debug ElapsedMilliseconds()-t
 
t= ElapsedMilliseconds()
SS2$ = Space(SumL)
*pSS = @SS2$
For i = 0 To a-1
    LN=Len(ArrStr(i)); закоментировать если розкоментировать следующую строку
;ниже идут три варианта добавления в строчку
    ;CopyMemory(@ArrStr(i), *pSS, ArrLS(i)*2) :*pSS+ArrLS(i)*2
    ;CopyMemory(@ArrStr(i), *pSS, LN*2)
    PokeS(*pSS,ArrStr(i),LN*2)
    *pSS+LN*2
Next
Debug ElapsedMilliseconds()-t
 
;Debug SS2$;выводим содержимое строки, когда большая лучше ненужно
 


Не понятно причём тут массив строк?
Речь о том что расширить длину строки или данных(не важно каких лишь бы не потерять связь с ними в памяти).
Почему говорю про строку(потому что нужна для дальнейшего использования на выходе( после всяких манипуляций с данными получить строку))
но динамическая память тоже нужна(так как работать с ней может оказаться эффективней)
Вот код как можно динамически без потерь данных(условно говоря в виде строки символов утф16)расширять её объём памяти.
Но что бы в данном случаи получить на выходе строку нужно будет её взять(прогнать через функцию peeks() )
и это быть может оказаться не эффективно по скорости по сравнению с первым примером в топике,
когда ненужно использовать peeks() :roll:
PS.В данном случае используя для расширения массив(все средства по своему хороши и пригодятся) :wink:
Этот пример демонстрирует только момент расширение в памяти .
Код:
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
34
35
36
37
 
Global Dim simvol${1}(9)
Debug "Базовый адрес   "+@simvol$(0)
 
PokeS(@simvol$(0),"1234567890",#PB_UTF16)
For i=0 To 9
  Debug simvol$(i)
Next
;
ReDim simvol${1}(20)
Debug "Базовый адрес   "+@simvol$(0)
Debug PeekS(@simvol$(0),-1,#PB_UTF16)
 
;===================================
 
ReDim stroka${1}(0)
Global rashetindexa.l=0
Global index.l=0
Global ST.s=#NULL$
 
MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100
     ReDim stroka${1}(q)
   Next
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100
     ST=LSet(ST,q,"")
   Next
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
;==================================
 
 


PSS:Хотел поменять заголовок вопроса на (Как ускорить конкатенацию?(И динамическое расширение данных) но сайт форум а не сделал этого :wink:


Последний раз редактировалось Сергейчик Чт окт 04, 2018 6:54 am, всего редактировалось 1 раз.

Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Чт окт 04, 2018 6:54 am 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Вт апр 14, 2009 7:22 pm
Сообщений: 362
Благодарил (а): 1 раз.
Поблагодарили: 13 раз.
Пункты репутации: 0
Сергейчик писал(а):
Не понятно причём тут массив строк?

Естественно не причём, просто на чём то нужно тестировать и это массив строк переменной длины разный при каждом запуске.

Я ещё раз прошу ответить на вопрос в чём главная задача? Зачем наращивать память по каждому чиху если заведомо известно, что это самое узкое место?
Почему нет возможности или хотя бы попытки найти компромисс и наращивать буфер для строки крупными порциями а мелкими манипулировать в уже захваченном у системы пространстве?

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

p.s.
Сергейчик писал(а):
Но что бы в данном случаи получить на выходе строку нужно будет её взять(прогнать через функцию peeks() )
В корне, в суте, в главном, ..... , заблуждение!!!
Поэтому настоятельно прошу напиши ЗАЧЕМ? Что потом с динамически или не динамически наращиваемом куском памяти содержащем нужные данные требуется дальше делать?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Чт окт 04, 2018 10:14 am 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Вт апр 14, 2009 7:22 pm
Сообщений: 362
Благодарил (а): 1 раз.
Поблагодарили: 13 раз.
Пункты репутации: 0
Ещё инфа для размышления:
Из справки:
Синтаксис Result = CopyMemoryString(*String [, @*DestinationMemoryID])
Описание Копирует строку с указанного адреса *String в область памяти с начальным адресом @*DestinationMemoryID, если он указан. Если последний параметр опущен, то строка копируется в конец целевой (приёмной) области памяти оставшейся от предыдущего вызова CopyMemoryString.
Параметры *String Адрес строки в памяти, которую требуется скопировать. Строка должна завершаться нулевым символом (#Null). Ожидается, что строка будет в формате строки PB.
@*DestinationMemoryID (Дополн.) Указатель на переменную, содержащую адрес с целевой областью памяти. После копирования строки переменная *DestinationMemoryID будет указывать на нуль-символ (#Null) в конце скопированной строки, поэтому следующий вызов функции CopyMemoryString добавит новую строку к предыдущей.

Если этот параметр опущен, будет использован конечный адрес предыдущего вызова функции CopyMemoryString. Соответственно первый вызов функции CopyMemoryString для данного буфера памяти, обязательно должен содержать параметр @*DestinationMemoryID.

Возвращаемое значениеВозвращает обновлённое значение *DestinationMemoryID после копирования строки.


Пример: Конкатенация строк (сращивание)

Код:
1
2
3
4
5
6
7
8
*Buffer = AllocateMemory(1000)
*Pointer = *Buffer
CopyMemoryString("Hello", @*Pointer)
CopyMemoryString(" World")  ; Эта строка встанет сразу после "Hello"
*Pointer-2                  ; Идём назад на 2 символа (на символ 'l' в 'World')
CopyMemoryString("LD")      ; Теперь последние символы будут в верхнем регистре.
Debug PeekS(*Buffer)
 



И казалось бы всё красиво, кроме PeekS(*Buffer), где лично мне не понятно что там под капотом Фрэд в данном случае делает, но просто указатель на строку в конструкцию debug вроде бы не вставишь.
Но
Код:
1
2
3
4
5
6
7
8
9
BS.s = Space(1000)
*Pointer = @BS
CopyMemoryString("Hello", @*Pointer)
CopyMemoryString(" World")
*Pointer-4
CopyMemoryString("LD")
Debug BS
BS = "" ; почти освобождаем память, почти FreeMemory(*MemoryID) )))
 


т.е. в тех местах где Пуребэйсик всётаки не Си и нужно это учитывать, есть 333 способа это учесть :mrgreen:

p.s. когда я говорю "не СИ" я имею ввиду места в которых типизованные указатели позволяют элегантно и просто написать что нужно делать с тем или иным местом в памяти, как его в данный момент воспринимать как последовательность двух байт, или например символ UTF16, или вообще 16-ти разрядное целое со знаком или без знака. В пурике, через StructureUnion всякое такое возможно, но не всегда логично выглядит.


Вернуться наверх
 Профиль  
 
СообщениеДобавлено: Пт окт 05, 2018 12:06 am 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
Сергейчик писал(а):
Не понятно причём тут массив строк?
Я буду отвечать по порядку, хоть и ниже есть ответы, если непротив :D , о чем я узная попозже, но уже поздно :lol: будеть.
Ну ... и пальцем так в сол верчу и стесняюсь, краснею, прям незнаю чего стаказть(просто смайлика подходящего нету вот и пишу руцями).

Надеюсь ты нетак миллион строк соединяеш.
Код:
1
2
3
4
5
6
a001$="54654fdgvfsd"
a002$="dsGFvd"
...
a1000000$="ldgjksdn"
 
itogo$=a001$+a002$+...a1000000$

:lol: :shock:
гдето нужно какието строки хранить, но проще в строковом масиве, с кудова их извлекать.
Ну мож в буфере памяти Mem=AllocateMemory(100000000) и с тудова както извлекать и соединять.
К стати можно и так, только прошерстить на наличие нулевого бита и в место него чегото
подставить например пробел, главное заранее выделить побольше пмяти, и только пеекС()
и всталвляй куда нужно(учет анси и уникода тоже нужен-один или два ноля).

:?: Вопрос к тебе с чего будут браться даные для добавления в переменную,
тебе этот вопрос задавали но ответ... с клавы или - ваш вариант :) .

Неответил и ты на мой вопрос-
Цитата:
все одно вопрос остается как узнать, что оно действительно выделено при пустых кавычках.
это в контексте stroka$=LSet(stroka$,rashetindexa,"")

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

Ты пишеш о LSet(stroka$,rashetindexa,"")
Цитата:
поэтому и не происходит у меня в примере
переполнения памяти и вылета проги.
я отвечаю
Цитата:
я сделал такой код и
невылетела прога это приятно, но выделив 100 метров прога сожрала 410 метров ,
мож непрочитал, бывает. на каждый выделеный байт своровать 4, это как называется если
неутечка :roll: ну я незнаю, конеха если у тебя ПК 4 Гига, то что тут мелочиться с такими
размерчиками.

вот последний мой пример с добавлением рамера памяти без разрушения содержимого,
ты его тестил? Что ненравится в нем, может баги какието.... я же немогу знать какие
особенности твоего кода, хоть напиши чегото. Этот кусок создает и увеличивает размер
буфера неразрушая содержимого, пурик просто его вместо тебя переносит.
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dim a.b(20)
ln=PokeS(@a.b(0),"Sos")
Debug PeekS(@a.b(0))
Debug @a()
Debug @a(0)
ReDim a.b(10000000); выделяем 100 метров
Debug PeekS(@a.b(0))
Debug @a()
ln=PokeS(@a.b(0)+ln,"123"); добавляем даные в конец, тут нужно учитывать что уникод имеет двабайта на символ
; хотя чего я несу, у тебя ln=PokeS() выдает сколько байт записала, эти и есть смещение в
;байтах относительно старта, в даном случае стартовали с адреса нолевого @a.b(0)
Debug PeekS(@a.b(0))
 
;Delay(10000); в этот момент за 10 сек смотрим скоко прога схавала памяти

как видим
;адреса поменялись для масива, но содержимое осталось целым,
ну прям как тебе нужно и это даже не в тему вопроса форума -"Как ускорить конкатенацию?",
это ответ на очередной попутный вопрос.
Почему я использую указатель адреса так @a() или @a(0)(обычно свегда так) вместо того чтобы
присвоить переменной, да потому что видиш сам адрес изменился, поэтому так правильней.
Но если после ReDim ты присвоеш переменной заново адрес, проблем небудет, я тоже пример
проги приводил к этому вопросу.

Вот второй вариант
Код:
1
2
3
4
5
6
7
8
9
10
11
12
M = AllocateMemory(10):;Debug MemorySize(M); размер
ln=PokeS(M,"123"):  Debug ln: ;УЗНАЕМ Сколько байт занял текст  в памяти с этого места и плясать дальше
Debug PeekS(M); смотрим содержимое
M2 = AllocateMemory(20); если мало памяти запрашиваем больше
;CopyMemoryString("Hello", @*Pointer)4 можно этим поиграться на досуге.
 
MoveMemory(M, M2, 10); или ln , и копируем сюда наш текст или даные со старого места.
FreeMemory(M); удОляем старый участок памяти, указетель на него нерабочий больше
Debug PeekS(M2); читаем содержимое которое должно быть таким самым как и мы запхали в первый участок ОЗУ
 
ln=PokeS(M2+ln," Hello друзъя"); к нашему тексту, в новом ОЗУ, ДОПИСЫВАЕМ ЕЩЕ ТЕКСТ
Debug PeekS(M2); читаем с копии(а оригинала уже и так нет, то это и есть оригинал) что дописали в конец



только ReDim гораздо проще, но все остается таким самым, ReDim короче на две строчки
Код:
1
2
3
M2 = AllocateMemory(20)
MoveMemory(M, M2, 10)
FreeMemory(M)


Ну и еще один пример приводил,но его после тестов я зарубил и где он на фаруме встретился я ниже написал китайское предупреждение что это лажа.

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

Цитата:
и это быть может оказаться не эффективно по скорости по сравнению с первым
примером в топике,когда ненужно использовать peeks()
непойму о чем это ты или
прикалываемся понемногу, вот десять метров в уникоде это 20 метров получется, перегнал в
другую переменную без проблем, шо знач не эффективно? или тебе нужно за 1 мкс перегнать
:lol:
Код:
1
2
3
4
5
6
7
a$="123"+Space(10000000)+"5432"
t=ElapsedMilliseconds()
b$=PeekS(@a$)
;время прогона как ті сказал не
Debug ElapsedMilliseconds()-t
Debug Len(a$)
Debug Len(b$)

78
10000007
10000007
Цитата:
PSS:Хотел поменять заголовок вопроса на (Как ускорить конкатенацию?(И динамическое расширение данных) но сайт форум а не сделал этого
он сделал это, но у некоторых людей возникае проблема с этим и они востановили имя назад, сам видел как вдург чегото ветка сменила название, а потом смотрю опять старое, причину спрашивай у модераторов.

jobless спасибо за напоминание, я ему писал проэто, да и Пётр давал сразу, а мы нашли кучу решений ещё. Помниш эту строчку
Код:
1
;CopyMemoryString("Hello", @*Pointer)4 можно этим поиграться на досуге.

:lol:

прикольный пример дал Петр, надо поиграться еще и сним.
Код:
1
2
3
4
5
6
7
*Buffer = AllocateMemory(1000)
*Pointer = *Buffer
CopyMemoryString("Hello", @*Pointer)
CopyMemoryString(" World")  ; Эта строка встанет сразу после "Hello"
*Pointer-2                  ; Идём назад на 2 символа (на символ 'l' в 'World')
CopyMemoryString("LD")      ; Теперь последние символы будут в верхнем регистре.
Debug PeekS(*Buffer)



Что это в твоем коде, что дают эти фигурные скобки Global Dim simvol${1}(9)?
Хоть и пурик неругается и менно на эту строку, а дальше еще как, но таких параметров в вправке нету.
из справки - "В отличие от переменной, после имени Массива всегда указываются круглые скобки ( ), или квадратные скобки [ ] в случае статического Массива."
Ага нашел в старшей версии
Dim a${1}(2000) ; Массив для 2000 строк с ограничением в 1 символ на строку.


Блин думаю чего пурик меня начал бесить, а я вместо 5.6 версии открыл 4.0 и чегото хочу от него получить. :roll:
короче немного переделал под рабочий вариант, результат - неуд(-ачный).
И не пойму зачем ты пихаеш переменные как глобальные, ведь тут они не к чему, просто лишняя писанина или просто привычка правильно программировать :)
Код:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Dim simvol${1}(9)
simvol$(0)=""
Debug "Базовый адрес   "+Str(@simvol$(0) )
 
;PokeS(@simvol$(0),"1234567890",#PB_UTF16)
PokeS(@simvol$(0),"Пцички 890",#PB_UTF16); мож так будет в UTF16, хотя больше на уникод похоже
For i=0 To 9
  Debug simvol$(i)
Next
;
ReDim simvol${1}(20)
Debug "Базовый адрес   "+Str(@simvol$(0) )
Debug PeekS(@simvol$(0),-1,#PB_UTF16)
 
;===================================
 
;ReDim stroka${1}(0);тут ты пытаешся изменить размер НЕСУЩЕСТВУЮЩЕГО МАСИВА это как?
Dim stroka${1}(0)
rashetindexa.l=0
index.l=0
ST.s=#NULL$
 
MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100000
       ; ну тут неполохо получилось, побукве вставлять можно
       ; но непроще сразу выделить большой кусок и сравнивать на переполнение
     ReDim stroka${1}(q)
   Next
   t = (GetTickCount_() - time)
Debug "Количество  циклов=" + StrF(q) + #CR$ + "Время теста= " + StrF(t/1000)
   
MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100000
       ST.s=LSet(ST,q,"")
       ;aa$+"1"
       ;введу тормознутости этой идеи я ввел индикатор циклов
       ;(недумай что помешает сильно на результат ,мож закоментировать и убедится, только на тысячную часть)
       If q & $8ff=$8ff:Debug q:;Debug @ST:
       EndIf
       ;заметь как с ростом длинны строки начинает медлянеть, в отличии от ReDim
       
   Next
   t2 = (GetTickCount_() - time)
  Debug "Количество  циклов=" + StrF(q) + #CR$ + "Время теста= " + StrF(t2/1000)
;==================================
 Debug "восколько раз твоя идея медленнее=" + StrF(t2/t)
 



результат теста:
ReDim
Количество циклов=100001 на 100 килограм текста
Время теста= 0.0149999997 8)

ST.s=LSet(ST,q,"")
Количество циклов=100001
Время теста= 21.9060001373 :roll:
восколько раз твоя идея медленнее=1460.4000244141 :shock: да очень быстро получилось я фшЁке. Наверное тебе стоит забросить такую идею

Кстати обычное соединение строк aa$+"1" дало такое врямя
Время теста= 50.6879997253
восколько раз твоя идея медленнее=1635.0968017578
НЕ ГУСТО БЫСТРО, для небольшой длинны годится в 2 раза побыстрей от атаки влоб.
Чего ты в этот медленный метод вцепился.

Немного подзабавила справка для пурика 5.21
The string format to use when writing the string. This can be one of the following values:
#PB_Ascii : Writes the strings in ascii
#PB_UTF8 : Writes the strings in UTF8
#PB_Unicode: Writes the strings in unicode
The default is #PB_Unicode if the program is compiled in unicode mode and #PB_Ascii otherwise.
А где подевались, главное неругается и даже чегото делает
Debug #PB_UTF16
Debug #PB_UTF16BE
Debug #PB_Unicode;

:?: Розкажи лучше задачу, тебя уже в который раз просят.
Понятно что строки в кучу слепить.
Одкуда исходные даные этих строк, в чём хранить будиш(масив или?)
Куда пхать строку думаю неважно знать.

Я вижу ты начал осваиваться с масивами.

_________________
искатель истины


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Пт окт 05, 2018 11:14 am 
Не в сети
профессор

Зарегистрирован: Пн июл 22, 2013 11:00 pm
Сообщений: 656
Благодарил (а): 2 раз.
Поблагодарили: 34 раз.
Пункты репутации: 9
В общем мучился я с этим redim упорно(так как у пурика слабое место со стеком когда его код и асм вставки)
Получилось вроде контролировать переполнение памяти.
и да чем выше изначально её объём тем выше скорость(если делаем часто redim(плюс контроль нового адреса)то скорость падает(это так сказать узкое место(+может лишние телодвижения в стеке))) :roll:
Код:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
 
 Global r.i
Global Dim stroka2${1}(0)
Global MemoryString_BazovyiAdres.i
Global MemoryString_AdresCursora.l
Global MemoryString_AdresLimita.l
Global MemoryString_realwcslen.l
Global MemoryString_smehenie.l
;
 
Procedure.i AllocateMemoryString(kolihestvosimvolov.l,Limit.i);можно сделать структурой и назначением номера строки
  ReDim stroka2${1}(kolihestvosimvolov)
      MemoryString_realwcslen=kolihestvosimvolov
      MemoryString_smehenie=kolihestvosimvolov
      MemoryString_BazovyiAdres=@stroka2$(0)
      ;MemoryString_AdresPoslednegoSimvola=MemoryString_BazovyiAdres+(kolihestvosimvolov*2)-2
      MemoryString_AdresLimita=MemoryString_BazovyiAdres+(Limit*2)-2
      MemoryString_AdresCursora=MemoryString_BazovyiAdres
   ProcedureReturn MemoryString_BazovyiAdres
EndProcedure
Procedure.i Set_MemoryString(MemoryBuffer,Text.s,Lenght,Flags);после переделаю на свою
 
  If MemoryString_BazovyiAdres>MemoryBuffer And MemoryString_AdresPoslednegoSimvola<MemoryBuffer;-200
    ;Debug "error"
    MessageRequester("ErrorMemoryString","Указанный Адрес за пределом строки")
  ElseIf MemoryString_BazovyiAdres=MemoryBuffer
    Debug "rrrrrrrrrrr"
        If Lenght=-1
      Lenght=Len(Text)
        EndIf
        ;ReallocateMemoryString(Lenght)
 
        MemoryString_AdresCursora=MemoryString_BazovyiAdres+PokeS(MemoryString_BazovyiAdres,Text,Lenght,Flags)
  ; Else
       
    EndIf
EndProcedure
Macro Get_MemoryString(MemoryBuffer,Lenght,Flags)
 PeekS(MemoryBuffer,Lenght,Flags)
EndMacro
Macro Free_MemoryString()
 ReDim stroka2${1}(0)
EndMacro
Procedure Concatenatiy_MemoryString(*strokka)
    ;!mov dword [v_r],esp
    ;MessageRequester("",Str(r))
    ;MessageRequester("","*stroka  "+Str(*strokka))
 !mov dword eax,[v_MemoryString_AdresLimita]
 !cmp dword eax,[v_MemoryString_AdresCursora]
 !ja net
  ;If MemoryString_AdresCursora>MemoryString_AdresLimita;
    MemoryString_realwcslen+MemoryString_smehenie
  ;;============
  ;!mov dword eax,[v_MemoryString_smehenie]
 ;!add dword [v_MemoryString_realwcslen],eax
  ;!add dword eax,eax;
  ;!add dword [v_MemoryString_AdresLimita],eax
    MemoryString_AdresCursora-MemoryString_BazovyiAdres
    MemoryString_AdresLimita+(MemoryString_smehenie*2)
    MemoryString_AdresLimita-MemoryString_BazovyiAdres
  ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
 
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
       ; MessageRequester("","MemoryString_realwcslen "+Str(MemoryString_realwcslen))
 
    ReDim stroka2${1}(MemoryString_realwcslen)
   
  MemoryString_BazovyiAdres=@stroka2$(0)
  ;MessageRequester("","MemoryString_BazovyiAdres "+Str(@stroka2$(0)))
  MemoryString_AdresCursora+MemoryString_BazovyiAdres
  MemoryString_AdresLimita+MemoryString_BazovyiAdres;+(MemoryString_smehenie*2)
     ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
     ;   MessageRequester("","MemoryString_AdresLimita "+Str(MemoryString_AdresLimita))
 
 
  ;;==========================
;EndIf
  !net:
 !PUSH esi
  !PUSH edi
  !mov dword esi,[esp+24]
  !mov dword edi,[v_MemoryString_AdresCursora]
 ; !mov dword [v_r],esi
  ;MessageRequester("","stroka esi "+Str(r))
 
   !cmp word[esi],0h
   !jz skopirovali66
  !ysseok66:
 !mov word ax,[esi]
  !mov word[edi],ax
  !add dword esi,2
  !add dword edi,2
  ;!jmp ysseok66
   !cmp word[esi],0h
   !jnz ysseok66
   !skopirovali66:
  !mov word[edi],0h
   !mov dword [v_MemoryString_AdresCursora],edi
  !pop edi
  !pop esi
   ; !mov dword [v_r],esp
  ;MessageRequester("",Str(r))
 ;!mov dword [v_r],esp
 ; MessageRequester("",Str(r))
;!add dword esp,12
  ;!retn 4
EndProcedure
 
AllocateMemoryString(200000000,199999900)
If OpenWindow(0, 0, 0,600,800, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8,560, 780)
     
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100000000
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Concatenatiy_MemoryString(@"6")
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Next
 
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
    SetGadgetText(0,PeekS(@stroka2$(0),-1,#PB_UTF16))
        ReDim stroka2${1}(0)
 
*Buffer = AllocateMemory(200000000)
Global *Pointer = *Buffer
  MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100000000
 
CopyMemoryString("6", @*Pointer)                
Next
   
 
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
  SetGadgetText(0,PeekS(*Buffer,-1,#PB_UTF16))
  FreeMemory(*Buffer)
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
   EndIf
 


Переделал подглядев как он компилит.... :D
Код:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
 
 Global r.i
Global Dim stroka2${1}(0)
Global MemoryString_BazovyiAdres.i
Global MemoryString_AdresCursora.l
Global MemoryString_AdresLimita.l
Global MemoryString_realwcslen.l
Global MemoryString_smehenie.l
;
 
Procedure.i AllocateMemoryString(kolihestvosimvolov.l,Limit.i);можно сделать структурой и назначением номера строки
  ReDim stroka2${1}(kolihestvosimvolov)
      MemoryString_realwcslen=kolihestvosimvolov
      MemoryString_smehenie=kolihestvosimvolov
      MemoryString_BazovyiAdres=@stroka2$(0)
      ;MemoryString_AdresPoslednegoSimvola=MemoryString_BazovyiAdres+(kolihestvosimvolov*2)-2
      MemoryString_AdresLimita=MemoryString_BazovyiAdres+(Limit*2)-2
      MemoryString_AdresCursora=MemoryString_BazovyiAdres
   ProcedureReturn MemoryString_BazovyiAdres
EndProcedure
Procedure.i Set_MemoryString(MemoryBuffer,Text.s,Lenght,Flags);после переделаю на свою
 
  If MemoryString_BazovyiAdres>MemoryBuffer And MemoryString_AdresPoslednegoSimvola<MemoryBuffer;-200
    ;Debug "error"
    MessageRequester("ErrorMemoryString","Указанный Адрес за пределом строки")
  ElseIf MemoryString_BazovyiAdres=MemoryBuffer
    Debug "rrrrrrrrrrr"
        If Lenght=-1
      Lenght=Len(Text)
        EndIf
        ;ReallocateMemoryString(Lenght)
 
        MemoryString_AdresCursora=MemoryString_BazovyiAdres+PokeS(MemoryString_BazovyiAdres,Text,Lenght,Flags)
  ; Else
       
    EndIf
EndProcedure
Macro Get_MemoryString(MemoryBuffer,Lenght,Flags)
 PeekS(MemoryBuffer,Lenght,Flags)
EndMacro
Macro Free_MemoryString()
 ReDim stroka2${1}(0)
EndMacro
Procedure Concatenatiy_MemoryString(*strokka)
    ;!mov dword [v_r],esp
    ;MessageRequester("",Str(r))
    ;MessageRequester("","*stroka  "+Str(*strokka))
 !mov dword eax,[v_MemoryString_AdresLimita]
 !cmp dword eax,[v_MemoryString_AdresCursora]
 !ja net
  ;If MemoryString_AdresCursora>MemoryString_AdresLimita;
   ; MemoryString_realwcslen+MemoryString_smehenie
   ;  MemoryString_AdresLimita+(MemoryString_smehenie*2)
   ;  MemoryString_AdresLimita-MemoryString_BazovyiAdres
    ;  MemoryString_AdresCursora-MemoryString_BazovyiAdres
  ;;============
  !mov dword eax,[v_MemoryString_smehenie]
  !add dword [v_MemoryString_realwcslen],eax
  !add dword eax,eax;
  !add dword [v_MemoryString_AdresLimita],eax
  !mov dword eax,[v_MemoryString_BazovyiAdres]
  !sub dword [v_MemoryString_AdresLimita],eax
  !sub dword [v_MemoryString_AdresCursora],eax
 
 
  ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
 
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
       ; MessageRequester("","MemoryString_realwcslen "+Str(MemoryString_realwcslen))
 
    ReDim stroka2${1}(MemoryString_realwcslen)
   
  MemoryString_BazovyiAdres=@stroka2$(0)
  ;MessageRequester("","MemoryString_BazovyiAdres "+Str(@stroka2$(0)))
  ;MemoryString_AdresCursora+MemoryString_BazovyiAdres
  ;MemoryString_AdresLimita+MemoryString_BazovyiAdres
     ; !mov dword eax,[v_MemoryString_BazovyiAdres];
      !add dword [v_MemoryString_AdresCursora],eax
      !add dword [v_MemoryString_AdresLimita],eax
 
   
     ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
     ;   MessageRequester("","MemoryString_AdresLimita "+Str(MemoryString_AdresLimita))
 
 
  ;;==========================
;EndIf
  !net:
 ;!PUSH esi
  ;!PUSH edi
  !mov dword ebx,[esp+12]
 
 ; !mov dword [v_r],esi
  ;MessageRequester("","stroka esi "+Str(r))
 
   !cmp word[ebx],0h
   !jz vyhod
   !mov dword ebp,[v_MemoryString_AdresCursora]
  !ysseok66:
 !mov word ax,[ebx]
  !mov word[ebp],ax
  !add dword ebx,2
  !add dword ebp,2
   !cmp word[ebx],0h
   !jnz ysseok66
   !skopirovali66:
  !mov word[ebp],0h
   !mov dword [v_MemoryString_AdresCursora],ebp
   !vyhod:
 ;!pop edi
  ;!pop esi
   ; !mov dword [v_r],esp
  ;MessageRequester("",Str(r))
 ;!mov dword [v_r],esp
 ; MessageRequester("",Str(r))
;!add dword esp,12
  ;!retn 4
EndProcedure
 
AllocateMemoryString(500000000,499999900)
;AllocateMemoryString(5,2)
If OpenWindow(0, 0, 0,600,600, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8,560, 580)
     
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 5000000;0;0
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Concatenatiy_MemoryString(@"Hello word! ")
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Next
 
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
    SetGadgetText(0,PeekS(@stroka2$(0),-1,#PB_UTF16))
        ReDim stroka2${1}(0)
 
*Buffer = AllocateMemory(500000000)
Global *Pointer = *Buffer
  MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 5000000;0;0
 
CopyMemoryString("Hello word! ", @*Pointer)                
Next
   
 
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
  SetGadgetText(0,PeekS(*Buffer,-1,#PB_UTF16))
  FreeMemory(*Buffer)
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
 



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Сб окт 06, 2018 11:12 pm 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
Сергейчик
Это не прога, это какойо монстр, сожрало памяти на гиг :shock: и это для какогото текста, подвесила ПК, ели удалил.

Хочь обогнать простое копирование так и сделай, у тебя на асме это легко получится.

Мож мне написать на асме простую проверку достижения конца строки-проверка на ноль для одного байта(анси) и для двух(уникод), для ускорения просчета длинны.
Только ненужно заворачивать код и в процедуру бросать.
Входящие даные:
адрес начала
адрес конца или длинна участка памяти
берем байт по адресу и сравниваем на ноль кажется TEST
потом проверка результата на ноль jz или jnz уже непомню.
На выходе адрес где нашел ноль, признак конца строки.
Тебе это легко, а мне вспоминать то что лет 20 назад было...

Вот код с контролем переполнения буфера и самоконтролем при добавлении строки.
Остальное можно свтавить, я уже давал код с перемещением в памяти и в масиве
Код:
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
ln=100000005
*Buffer = AllocateMemory(ln)
  *Pointer = *Buffer
  CopyMemoryString("", @*Pointer)
 
  t=ElapsedMilliseconds()
 
  a$="*"
For i=0 To 100000000
    a$="*"+Str(i)
    l=StringByteLength(a$)
    ;Debug l
    ;Debug i
    ;Debug StringByteLength(PeekS(*Buffer))
    ;контроль буфера переполнения, тут можно делать релок для масива.
    ;или для памяти как тут создаеш больший буфер и в него копируеш, а старый удаляеш.
    If *Pointer-*Buffer+l>ln-0:
       Break:;ПРЕРЫВАЕМ ЦИКЛ по достижению предела памяти, сообщаем, или увеличиваем блок камяти
    EndIf;ln-2 это для уникода,
    CopyMemoryString(a$);+Str(i))
    ;Debug i
    ;Debug "1-----------"
Next
Debug "2-----------"
Debug StrD( (ElapsedMilliseconds()-t)/1000)
Debug i
; Debug PeekS(*Buffer);смотрим содержимое памяти
Debug StringByteLength(PeekS(*Buffer)); сколько заняло в памяти байт, недолжно былть больше чем выделили
 


100 метров за:
3.25
6388889
100000004

А чего тебе нравится односимвольный масив stroka2${1}(0) по идее так тож работает stroka2.w(0).

_________________
искатель истины


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Вс окт 07, 2018 12:08 pm 
Не в сети
профессор

Зарегистрирован: Пн июл 22, 2013 11:00 pm
Сообщений: 656
Благодарил (а): 2 раз.
Поблагодарили: 34 раз.
Пункты репутации: 9
Какие 3 сек?вы издеваетесь :?:
У вас там переменные к тому же разные :!:
По поводу lset("")можете посмотреть тем же вашим любимом peek(), bin()что там добавится. :roll:
Отдельная процедура предпочтительней тем что уменьшает код программы так как проверка внутри процедуры. я же не в цикле её гоняю а конкатинирую строки ,которых возможно будет много в зависимости от условия выполнения проги:D
Использование строкового массива навеяло из за того что бы избавится от peeks()
если она жрет так много памяти?по сравнению с байтовым массивом то можно и отказаться.
Код:
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
 
ln=200000100;символы утф16
*Buffer = AllocateMemory(ln)
  *Pointer = *Buffer
  CopyMemoryString("", @*Pointer)
 
 
  limit=*Buffer+200000000
 
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
For i=0 To 200000100 Step 2;i сейчас в процедуре это адрес курсора типа *Pointer(смещенное значение)
 
    If *Pointer>limit;проверка за выход лимита
        Goto tt:;ПРЕРЫВАЕМ ЦИКЛ по достижению предела памяти, сообщаем, или увеличиваем блок камяти
        ;;REAllocateMemory(ln+добавка)
    EndIf;ln-2 это для уникода,
    CopyMemoryString("6")
Next
 tt:
  t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
  FreeMemory(*Buffer)
 
 



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Вс окт 07, 2018 1:53 pm 
Не в сети
профессор

Зарегистрирован: Пн июл 22, 2013 11:00 pm
Сообщений: 656
Благодарил (а): 2 раз.
Поблагодарили: 34 раз.
Пункты репутации: 9
Вот потесть :roll:
Код:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
 
 Global r.i
Global Dim stroka2${1}(0)
Global MemoryString_BazovyiAdres.i
Global MemoryString_AdresCursora.l
Global MemoryString_AdresLimita.l
Global MemoryString_realwcslen.l
Global MemoryString_smehenie.l
;
 
Procedure.i AllocateMemoryString(kolihestvosimvolov.l,Limit.i);можно сделать структурой и назначением номера строки
  ReDim stroka2${1}(kolihestvosimvolov)
      MemoryString_realwcslen=kolihestvosimvolov
      MemoryString_smehenie=kolihestvosimvolov
      MemoryString_BazovyiAdres=@stroka2$(0)
      ;MemoryString_AdresPoslednegoSimvola=MemoryString_BazovyiAdres+(kolihestvosimvolov*2)-2
      MemoryString_AdresLimita=MemoryString_BazovyiAdres+(Limit*2)-2
      MemoryString_AdresCursora=MemoryString_BazovyiAdres
   ProcedureReturn MemoryString_BazovyiAdres
EndProcedure
Procedure.i Set_MemoryString(MemoryBuffer,Text.s,Lenght,Flags);после переделаю на свою
 
  If MemoryString_BazovyiAdres>MemoryBuffer And MemoryString_AdresPoslednegoSimvola<MemoryBuffer;-200
    ;Debug "error"
    MessageRequester("ErrorMemoryString","Указанный Адрес за пределом строки")
  ElseIf MemoryString_BazovyiAdres=MemoryBuffer
    Debug "rrrrrrrrrrr"
        If Lenght=-1
      Lenght=Len(Text)
        EndIf
        ;ReallocateMemoryString(Lenght)
 
        MemoryString_AdresCursora=MemoryString_BazovyiAdres+PokeS(MemoryString_BazovyiAdres,Text,Lenght,Flags)
  ; Else
       
    EndIf
EndProcedure
Macro Get_MemoryString(MemoryBuffer,Lenght,Flags)
 PeekS(MemoryBuffer,Lenght,Flags)
EndMacro
Macro Free_MemoryString()
 ReDim stroka2${1}(0)
EndMacro
Procedure Concatenatiy_MemoryString(*strokka)
    ;!mov dword [v_r],esp
    ;MessageRequester("",Str(r))
    ;MessageRequester("","*stroka  "+Str(*strokka))
 ;!mov dword eax,[v_MemoryString_AdresLimita]
 ;!cmp dword eax,[v_MemoryString_AdresCursora]
 ;!ja net
  ;If MemoryString_AdresCursora>MemoryString_AdresLimita;
   ; MemoryString_realwcslen+MemoryString_smehenie
   ;  MemoryString_AdresLimita+(MemoryString_smehenie*2)
   ;  MemoryString_AdresLimita-MemoryString_BazovyiAdres
    ;  MemoryString_AdresCursora-MemoryString_BazovyiAdres
  ;;============
 
     ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
     ;   MessageRequester("","MemoryString_AdresLimita "+Str(MemoryString_AdresLimita))
 
 
  ;;==========================конкктенация
  !mov dword ebx,[esp+12]
   !cmp word[ebx],0h
   !jz vyhod
   !mov dword ebp,[v_MemoryString_AdresCursora]
  !ysseok66:
 !mov word ax,[ebx]
  !mov word[ebp],ax
  !add dword ebx,2
  !add dword ebp,2
   !cmp word[ebx],0h
   !jnz ysseok66
   !skopirovali66:
  !mov word[ebp],0
   !mov dword [v_MemoryString_AdresCursora],ebp
     ;;==========================================проверка размера буфера
   !cmp dword [v_MemoryString_AdresLimita],ebp;сравниваем адрес курсора с адресом лимита
   !ja vyhod
  !mov dword eax,[v_MemoryString_smehenie]
  !add dword [v_MemoryString_realwcslen],eax
  !add dword eax,eax;
  !add dword [v_MemoryString_AdresLimita],eax
  !mov dword eax,[v_MemoryString_BazovyiAdres]
  !sub dword [v_MemoryString_AdresLimita],eax
  !sub dword [v_MemoryString_AdresCursora],eax
 
 
  ;     MessageRequester("","MemoryString_BazovyiAdres "+Str(MemoryString_BazovyiAdres))
 
   ; MessageRequester("","MemoryString_AdresCursora "+Str(MemoryString_AdresCursora))
       ; MessageRequester("","MemoryString_realwcslen "+Str(MemoryString_realwcslen))
 
    ReDim stroka2${1}(MemoryString_realwcslen)
   
  MemoryString_BazovyiAdres=@stroka2$(0)
  ;MessageRequester("","MemoryString_BazovyiAdres "+Str(@stroka2$(0)))
  ;MemoryString_AdresCursora+MemoryString_BazovyiAdres
  ;MemoryString_AdresLimita+MemoryString_BazovyiAdres
     ; !mov dword eax,[v_MemoryString_BazovyiAdres];
      !add dword [v_MemoryString_AdresCursora],eax
      !add dword [v_MemoryString_AdresLimita],eax
 
    ;
   !
   !vyhod:
  !pop ebx
   !pop ebp
   !retn 4
EndProcedure
 
AllocateMemoryString(500000000,500000000)
;AllocateMemoryString(5,2)
If OpenWindow(0, 0, 0,600,600, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8,560, 580)
     
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
   For q=1 To 100000000
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Concatenatiy_MemoryString(@"6")
  ;!mov dword [v_r],esp
  ;MessageRequester("",Str(r))
Next
 
   t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
 ; SetGadgetText(0,PeekS(@stroka2$(0),-1,#PB_UTF16))
  ;SetGadgetText(0,PeekS(@stroka2$(6),4,#PB_UTF16))
 
       ReDim stroka2${1}(0)
;;===============================
ln=500000000;символы утф16
*Buffer = AllocateMemory(ln)
  *Pointer = *Buffer
  CopyMemoryString("", @*Pointer)
 
 
  limit=*Buffer+500000000
 
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
For i=1 To 100000000;i сейчас в процедуре это адрес курсора типа *Pointer(смещенное значение)
 
    If *Pointer>limit;проверка за выход лимита
        Goto tt:;ПРЕРЫВАЕМ ЦИКЛ по достижению предела памяти, сообщаем, или увеличиваем блок камяти
        ;;REAllocateMemory(ln+добавка)
    EndIf;ln-2 это для уникода,
    CopyMemoryString("6")
Next
 tt:
  t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
  FreeMemory(*Buffer)
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
 



Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Как ускорить конкатенацию?
СообщениеДобавлено: Вс окт 07, 2018 11:18 pm 
Не в сети
профессор

Зарегистрирован: Вс июл 05, 2009 5:55 pm
Сообщений: 313
Благодарил (а): 1 раз.
Поблагодарили: 10 раз.
Пункты репутации: 0
Сергейчик писал(а):
Какие 3 сек?вы издеваетесь :?:
Вот эти:
Вложение:
++2018.10.07-22-24-32.jpg [65.58 KiB]
Скачиваний: 0

Сергейчик писал(а):
У вас там переменные к тому же разные :!:

это вы о чем :?:
Это a$="*"+Str(i) ну, просто строка, можно масивом заменить где (i) ее индекс.
А если это If *Pointer-*Buffer+l>ln-0:, так это проверка на достижение конца буфера,
тестил вроде правильно дает прерывает цикл если больше чем нужно.
Можно не прерывать а удлинять буфер, думал вы догадаетесь,уже много примеров приводил.
По полочкам:*Pointer-*Buffer+l>ln-0:
*Pointer- адрес места куда будет писаться строка этим CopyMemoryString(a$)
*Buffer+ это начало всего выделеного ОЗУ,
а так *Pointer-*Buffer получаем смещение ну или длинну занятого строками CopyMemoryString(a$),
что в сумме дает сколько мы захотели впхать в нашу ОЗУ
l> это то что мы туда хотим влепить этим
ln-0 сравниваем с размером выделеного ОЗУ ели больше то выход, ну или ресайз делаем.
В же жаловались что нужно контроль переполнения буфера, так вот это и есть контроль.
А вы слишком много кода накодили чтобы получить результат и там таких контролей просто позавидуеш.

Я просил вас написать кусочек кода, наверное неполучилось. :roll:
Цитата:
Мож мне написать на асме простую проверку достижения конца строки-проверка на ноль для одного байта(анси) и для двух(уникод), для ускорения просчета длинны.
Только ненужно заворачивать код и в процедуру бросать.
Входящие даные:
адрес начала
адрес конца или длинна участка памяти
берем байт по адресу и сравниваем на ноль кажется TEST
потом проверка результата на ноль jz или jnz уже непомню.
На выходе адрес где нашел ноль, признак конца строки.
Тебе это легко, а мне вспоминать то что лет 20 назад было...



Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ln=200000100;символы утф16
*Buffer = AllocateMemory(ln)
  *Pointer = *Buffer
  CopyMemoryString("", @*Pointer)
 
 
  limit=*Buffer+200000000
 
    MessageRequester("", "Начало теста")
   time = GetTickCount_()
For i=0 To 200000100 Step 2;i сейчас в процедуре это адрес курсора типа *Pointer(смещенное значение)
 
    If *Pointer>limit;проверка за выход лимита
        Goto tt:;ПРЕРЫВАЕМ ЦИКЛ по достижению предела памяти, сообщаем, или увеличиваем блок камяти
        ;;REAllocateMemory(ln+добавка)
    EndIf;ln-2 это для уникода,
    CopyMemoryString("6")
Next
 tt:
  t.d = (GetTickCount_() - time)/1000
  MessageRequester("", "Количество  циклов=" + q + #CR$ + "Время теста= " + t)
  FreeMemory(*Buffer)


нужно контролировать в УТФ этот кусок текста строго CopyMemoryString("6") иначе указатель и переполнение и искажение даных вероятно и узнать реальную длинну можно только так и никак иначе StringByteLength("6").
Вот пример:
Код:
1
2
3
4
5
6
7
8
9
a$="123 QWE ЙЦУКЕН"
Debug Len(a$);тут только количество символов
Debug StringByteLength(a$,#PB_Ascii); тут один символ всегда занимает один байт
 
Debug StringByteLength(a$);это зависит от настроек компилятора
Debug StringByteLength(a$,#PB_Unicode); тут один символ всегда занимает два байта
 
Debug StringByteLength(a$,#PB_UTF8) ; а тут бабка на двое гадала : - \ получилась тройня, от и у вас такое будет
 



Цитата:
Вот потесть
Страшновато :evil: после предыдущего теста :lol: .
я нетестил.
Ну и ипять ты выделяеш гиг
AllocateMemoryString(500 000 000
и тут
ln=500 000 000
*Buffer = AllocateMemory(ln)
ну я сократил раз в 10, результата недождался, прибил прогу, ты шутиш:
за пол минуты сожрало уже с 100 до 500 метров и всего прошло q=7 500 000 циклов,
и что к полуночи окинчит :?:
For q=1 To 100 000 000
Concatenatiy_MemoryString(@"6")
Next
Шото оно меня невдохновляет. Уже тестить стремно :lol: .
Чего она так много берет памяти, а даже интересно под какие цели такой код.
Это случайно не из вопроса сколько закладок можно максимум создать(один на фаруме спросил), ну и ответ приблизительно 16 тыс., а я спросли а чего ты будиш делать с ними, ответ: а вдруг юзеру захчется столько создать. Забавный ответ, заставляет задуматься.

_________________
искатель истины


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 60 ]  На страницу Пред.  1, 2, 3, 4  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB