Оптимизация кода

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 20:38

Есть функция извлечения имени файла через цикл и Mid
Код: Выделить всё
Function ForMid(ByVal ps As String) As String
Dim i As Integer, f As Integer
Dim buf As String
f = Len(Trim(ps))

For i = f To 1 Step -1
    buf = Mid(ps, i, 1)
     If buf = "\" Then Exit For
    ForMid = buf + ForMid
Next i
End Function

Как я понимаю здесь есть строки, которые записаны неправильно в плане скорости работы.
Как оптимизировать этот код?

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 28.05.2016 (Сб) 20:49

Код: Выделить всё
Function ForMid(ByVal ps As String) As String
    Dim pos As Integer
    ps= Trim$(ps))
    Pos = InstrRev(ps, "\")
    ForMid = Mid$(ps, pos+1)
End Function

Вот как то так
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 20:59

Можешь построчно прокоментировать строки? Я понял как работает InstrRev, но не понял в случае с Mid, у него же 3 параметра?!

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 28.05.2016 (Сб) 21:10

Функция Mid
Mid(String,Start,[Length])
Mid$(String,Start,[Length])
MidB(String,Start,[Length])
MidB$(String,Start,[Length])


Параметры
String
Обязательный аргумент - строка, из которой извлекаются символы. Если аргумент имеет значение Null, возвращается Null
Start
Обязательный аргумент - значение типа Long. Позиция символа в строке String, с которого начинается нужная подстрока. Если Start больше числа символов в строке string, функция Mid возвращает пустую строку ("")
Примечание Если аргумент имеет отрицательное значение или равен 0, то генерируется ошибка времени исполнения
Length
Необязательный аргумент - значение типа Variant (Long). Число возвращаемых символов. Если этот аргумент опущен или превышает число символов, расположенных справа от позиции Start, то возвращаются все символы от позиции Start до конца строки
Примечание Если аргумент имеет отрицательное значение, то генерируется ошибка времени исполнения
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 21:20

:shock: ха! сколько с мидом работал, а вот простого и не знал! Спасибо!

Не знал что третий параметр Mid - необязательный!
Ты полностью функцию переписал!)) У меня есть подобная только через Instr и StrReverse
Последний раз редактировалось Don Leno 28.05.2016 (Сб) 21:27, всего редактировалось 1 раз.

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 21:26

Вопрос по моей функции:
Можно ли как нибудь заменить строку:
Код: Выделить всё
buf = "\"

И насколько помню как то подругому записывалась конкатенация строк:
Код: Выделить всё
ForMid = buf + ForMid

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 28.05.2016 (Сб) 22:00

Don Leno писал(а):И насколько помню как то подругому записывалась конкатенация строк:

ForMid = buf & ForMid Так обычно пишется

Don Leno писал(а):Можно ли как нибудь заменить строку:
Не уловил сути вопроса, а что на что нужно поменять то?

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

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 22:04

Я знаю просто я собираю все функции по извлечению имени файла. И этот код написал сам, а насчет
Код: Выделить всё
buf="\"
гдето писали что приравнивание строк это не очень правильно, как например:
Код: Выделить всё
if buf="" then..
правильнее
Код: Выделить всё
if len(buf)>0 then..
Вот и спрашиваю.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 28.05.2016 (Сб) 22:13

if len(buf)>0 then.. Применима только исключительно для проверки на пустую строку и не более, к твоему случаю это вообще никак не относится. И опять же приравнивание строк и сравнение операции суть разные. Конструкция a=b может быть и приравниванием и сравнением, все зависит от контекста применения, в твоем случае это сравнение, а не приравнивание.
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 28.05.2016 (Сб) 22:19

Спасибо за информацию, теперь буду знать)) Кстати, по длине кода, из всех что я собрал, твой самый минимальный и скоростной)))

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: Оптимизация кода

Сообщение pronto » 29.05.2016 (Вс) 2:40

Нет смысла хранить положение бэкслеша
Код: Выделить всё
Function ForMid(ByVal ps As String) As String
    ps = Trim$(ps)
    ForMid = Mid$(ps, InstrRev(ps, "\") + 1)
End Function
O, sancta simplicitas!

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 29.05.2016 (Вс) 6:26

Вот и код и сократился всего до пары строк :)
А если извернуться, то его можно и до одной сократить
Код: Выделить всё
Function ForMid(ByVal ps As String) As String
    ForMid = Mid$( Trim$(ps), InstrRev(Trim$(ps), "\") + 1)
End Function
, но это так для понта :), а вообще так конечно делать не нужно, ибо при таком подходе функция Trim$(ps) будет два раза вычисляться, а это уже не оптимально.
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 29.05.2016 (Вс) 9:21

Кстати, функция
Код: Выделить всё
Trim$(ps)
даже может не понадобиться, если заренее известно что в строка без лишних пробелов. Позволь добавить еще пару строчек кода к твоей функции:

Код: Выделить всё
Function ForMid(ByVal ps As String) As String
    ps = Trim$(ps)
if Len(ps)>0 then
    ForMid = Mid$(ps, InstrRev(ps, "\") + 1)
else
    ForMid = ps
end if
End Function

Тем самым получаем самописную функцию, которая возвращает имя файла из пути к нему, при этом если передать пустое значение, она не вызовет ошибок и вернет пустую строку.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 29.05.2016 (Вс) 9:27

А зачем так то ForMid = ps, тут ветвь Else вообще лишняя. Возвращаемая переменная и так инициализирована пустой строкой, так что лишнее присваивавшие тут вообще не к чему. А так конечно проверку на пустое значение нужно сделать.
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 29.05.2016 (Вс) 9:29

Точно ты как всегда прав:

Код: Выделить всё
Function ForMid(ByVal ps As String) As String
    ps = Trim$(ps)
if Len(ps)>0 then
    ForMid = Mid$(ps, InstrRev(ps, "\") + 1)
end if
End Function


Теперь гораздо лучше!

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Оптимизация кода

Сообщение Адская_Капча » 29.05.2016 (Вс) 10:23

Адская каптча научит настоящей оптимизации Изображение
Фтопку всякие Mid-ы и Trim-ы, лишний раз аллоцирующие строки =)

Код: Выделить всё
' Получение имени файла из пути: экстремально оптимизированная функция _
специально от Адской Капчи =)
Function GetFileName(ByVal lpsFilePath As Long) As String
   Dim lpEnd As Long, iTmp As Integer
   
   If lpsFilePath Then
      GetMem4 ByVal lpsFilePath - 4&, lpEnd
     
      For lpEnd = lpsFilePath + lpEnd - 2& To lpsFilePath Step -2
         GetMem2 ByVal lpEnd, iTmp: If iTmp - 32 Then Exit For 'Space
      Next
     
      For lpsFilePath = lpEnd To lpsFilePath Step -2
         GetMem2 ByVal lpsFilePath, iTmp: If iTmp = 92 Then Exit For '\
      Next
     
      PutMem4 ByVal VarPtr(GetFileName), SysAllocStringByteLen(lpsFilePath + 2, lpEnd - lpsFilePath)
   End If
End Function


Для случая, если вдруг разделителя "\" может не оказаться, а в начале есть пробелы - код чуть увеличится и модифицируется:
Код: Выделить всё
' Получение имени файла из пути: экстремально оптимизированная функция _
специально от Адской Капчи =)
Function GetFileName(ByVal lpsFilePath As Long) As String
   Dim lpEnd As Long, iTmp As Integer
   
   If lpsFilePath Then
      GetMem4 ByVal lpsFilePath - 4&, lpEnd 'Получение длины строки
     
      'Поиск позиции непробела с конца
      For lpEnd = lpsFilePath + lpEnd - 2& To lpsFilePath Step -2
         GetMem2 ByVal lpEnd, iTmp           'Получение кода текущего символа в памяти
         If iTmp - 32 Then Exit For          'Не пробел
      Next
     
      'Поиск "\" с конца, начиная с последнего непробела
      For lpsFilePath = lpEnd To lpsFilePath Step -2
         GetMem2 ByVal lpsFilePath, iTmp
         If iTmp = 92 Then Exit For '\
      Next
     
      'Поиск непробела с позиции, начиная с "\" + 2
      For lpsFilePath = lpsFilePath + 2 To lpEnd Step 2
         GetMem2 ByVal lpsFilePath, iTmp: If iTmp - 32 Then Exit For 'Space
      Next
     
      'Аллоцирование строки с вычисленными позициями
      PutMem4 ByVal VarPtr(GetFileName), SysAllocStringByteLen(lpsFilePath, lpEnd - lpsFilePath + 2)
   End If
End Function
Последний раз редактировалось Адская_Капча 29.05.2016 (Вс) 11:31, всего редактировалось 1 раз.

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 29.05.2016 (Вс) 11:05

1.Как я понимаю ты все делаешь в памяти?
2.
если вдруг разделителя "\" может не оказаться
- это ж как?
3. Прокоментишь код для непонимающего в этом?
4. И если не тяжело теорию расскажешь о работе этого кода?

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Оптимизация кода

Сообщение The trick » 29.05.2016 (Вс) 11:10

UA6527P

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 29.05.2016 (Вс) 11:26

The trick, ссылки у меня не открываются, пишет не удалось найти запрошенную страницу(((

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Оптимизация кода

Сообщение Адская_Капча » 29.05.2016 (Вс) 11:34

Комменты там добавились у второй версии функции

" file.txt "
В таком примере строки не будет найден разделитьель "\", потому начальная позиция будет как раз с самого начала, однако в начале могут быть и пробелы, поэтому первый код вернет в начале строку с пробелами...

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

Функции семейства Getmem - воистину замечательная вещь, они позволяют очень быстро получить значение в памяти по указателю =)

Те ссылки у меня тоже не открываются :((

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 29.05.2016 (Вс) 11:37

Don Leno писал(а):The trick, ссылки у меня не открываются, пишет не удалось найти запрошенную страницу(((
У меня тоже не открылись с тем же диагнозом
Бороться и искать, найти и перепрятать

Don Leno
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 421
Зарегистрирован: 13.10.2013 (Вс) 14:05

Re: Оптимизация кода

Сообщение Don Leno » 29.05.2016 (Вс) 11:43

Да нет же!
Я пишу функцию для извлечения имени файла из пути к нему
например:
"c:\windows\notepad.exe"
Где же там могут быть пробелы? Может излишним будет искать пробел? Скорее проще найти \ и считать все после этого символа

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 29.05.2016 (Вс) 12:32

Адская_Капча писал(а):Адская каптча научит настоящей оптимизации Фтопку всякие Mid-ы и Trim-ы, лишний раз аллоцирующие строки =)
Только никакая это не оптимизация. Мало того, что код не совсем правильный, так и никакой оптимальности тут нет. Ибо у тебя на каждой итерации цикла будет вызываться функция, а это упаковка в стек параметров и прочие накладные расходы на вызов, плюс в конце так же выделиться память и также будет копироваться строка. Так что производительность такого решения либо окажется аналогичным решению с функцией InstrRev, либо слегка хуже, хотя разница будет совсем крохотной. Поэтому вообще не понятно, ради чего городить такой огород. Смысла в этом нет никакого
Бороться и искать, найти и перепрятать

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Оптимизация кода

Сообщение Адская_Капча » 29.05.2016 (Вс) 12:44

Ну если в исходных строках точно нет пробелов, тогда можно искать только разделитель:

Код: Выделить всё
Function GetFileName(ByVal lpsFilePath As Long) As String
   Dim lpEnd As Long, iTmp As Integer
       
   If lpsFilePath Then
      GetMem4 ByVal lpsFilePath - 4&, lpEnd
         
      For lpsFilePath = lpsFilePath + lpEnd - 2& To lpsFilePath Step -2
         GetMem2 ByVal lpsFilePath, iTmp: If iTmp = 92 Then Exit For
      Next
         
      PutMem4 ByVal VarPtr(GetFileName), SysAllocString(lpsFilePath + 2&)
   End If
End Function


ger_kar, результаты получились медленнее, да? И где именно он неправильный?
Да и ТС не уточнил, новая строка должна возвращаться (исходный полный путь тоже нужен), или можно просто обрезать строку с путем?

GetMem-ы можно попытаться еще ускорить... Ведь это вызовы функций, верно, да и присваивание переменной здесь происходит...
У меня есть идея, как еще можно ускорить... Но возник вопрос: можно ли в TLB вшить свой ассемблерный код, но БЕЗ использования dll, кто в курсе?

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Оптимизация кода

Сообщение ger_kar » 29.05.2016 (Вс) 14:33

Адская_Капча писал(а):ger_kar, результаты получились медленнее, да?
Ну результаты практически одинаковые, да и то разница скорее всего - это результат погрешности измерений и это на 100 000 итераций, так что не стоит это того, что-бы огород такой городить вместо трех строчек кода.
Бороться и искать, найти и перепрятать

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 01.06.2016 (Ср) 18:28

Don Leno писал(а):The trick, ссылки у меня не открываются, пишет не удалось найти запрошенную страницу(((

Их по скобке постригли. Надо копировать адрес ссылки (не текст - в нём многоточие!), вставить в адресную строку, затем докопипастить хвост.

Ну или так:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa364963(v=vs.85).aspx


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Majestic-12 [Bot], SemrushBot и гости: 18

    TopList