итак, выходные - прекрасное время для флейма, офтопиков и некропостинга :-)
Признаю: когда я писал про лёгкость операции сравнения, то заблуждался.
В первую очередь я подразумевал оператор '===' из javascript. Но в vbs нет ничего подобного, да и строки там - не ссылочный тип. Впрочем, такой подход не сработает и в javascript - метод replace там всегда возвращает новую строку. В powershell объекты сравниваются по хэшу, но во-первых это не касается строк, во вторых он вычисляется не при создании объекта, а при вызове, поэтому всё равно отдельно перелопачивать весь массив данных.
Что касается приведённых измерений, то Compare-Object, к сожалению, вообще здесь неприменим, как и оператор -eq - они выполняют регистронезависимое сравнение строк. Что к тому же очевидно дольше.
тест скорости сравнения больших строк на PoSh разными методами
Код:
Describe 'Скорость сравнения длинных строк' {
$times = 100000
$lorem = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`n"
$originalString = $lorem * $times + '1'
$similarString = $lorem * $times + '1'
$modifiedString = $lorem * $times + '2'
Context 'сравнение оператором -eq' {
It 'разных строк' {
$originalString -eq $modifiedString | Should -BeFalse
}
It 'одинаковых строк' {
$originalString -eq $similarString | Should -BeTrue
}
It 'самой себя' {
$originalString -eq $originalString | Should -BeTrue
}
}
Context 'сравнение оператором -ceq' {
It 'разных строк' {
$originalString -ceq $modifiedString | Should -BeFalse
}
It 'одинаковых строк' {
$originalString -ceq $similarString | Should -BeTrue
}
It 'самой себя' {
$originalString -ceq $originalString | Should -BeTrue
}
}
Context 'сравнение методом Compare' {
It 'разных строк' {
$originalString.CompareTo($modifiedString) | Should -Be -1
}
It 'одинаковых строк' {
$originalString.CompareTo($similarString) | Should -Be 0
}
It 'самой себя' {
$originalString.CompareTo($originalString) | Should -Be 0
}
}
Context 'сравнение методом Equals' {
It 'разных строк' -ErrorAction SilentlyContinue {
$originalString.Equals($modifiedString) | Should -BeFalse
}
It 'одинаковых строк' {
$originalString.Equals($similarString) | Should -BeTrue
}
It 'самой себя' {
$originalString.Equals($originalString) | Should -BeTrue
}
}
Context 'сравнение командлетом Compare-Object' {
It 'разных строк' {
Compare-Object $originalString $modifiedString | Should -Not -BeNullOrEmpty
}
It 'одинаковых строк' {
Compare-Object $originalString $similarString | Should -BeNullOrEmpty
}
It 'самой себя' {
Compare-Object $originalString $originalString | Should -BeNullOrEmpty
}
}
Context 'сравнение командлетом Compare-Object -IncludeEqual' {
It 'разных строк' {
Compare-Object $originalString $modifiedString -IncludeEqual | Should -Not -BeNullOrEmpty
}
It 'одинаковых строк' {
Compare-Object $originalString $similarString -IncludeEqual | Should -Not -BeNullOrEmpty
}
It 'самой себя' {
Compare-Object $originalString $originalString -IncludeEqual | Should -Not -BeNullOrEmpty
}
}
Context 'сравнение хэшей' {
It 'разных строк' {
$originalString.GetHashCode() -eq $modifiedString.GetHashCode() | Should -BeFalse
}
It 'одинаковых строк' {
$originalString.GetHashCode() -eq $similarString.GetHashCode() | Should -BeTrue
}
It 'самой себя' {
$originalString.GetHashCode() -eq $originalString.GetHashCode() | Should -BeTrue
}
}
}
результаты теста
Код:
Describing Скорость сравнения длинных строк
Context сравнение оператором -eq
[+] разных строк 944ms
[+] одинаковых строк 84ms
[+] самой себя 84ms
Context сравнение оператором -ceq
[+] разных строк 127ms
[+] одинаковых строк 87ms
[+] самой себя 84ms
Context сравнение методом Compare
[+] разных строк 725ms
[+] одинаковых строк 688ms
[+] самой себя 701ms
Context сравнение методом Equals
[+] разных строк 94ms
[+] одинаковых строк 36ms
[+] самой себя 9ms
Context сравнение командлетом Compare-Object
[+] разных строк 959ms
[+] одинаковых строк 686ms
[+] самой себя 677ms
Context сравнение командлетом Compare-Object -IncludeEqual
[+] разных строк 717ms
[+] одинаковых строк 922ms
[+] самой себя 811ms
Context сравнение хэшей
[+] разных строк 110ms
[+] одинаковых строк 80ms
[+] самой себя 80ms
Так что доступные скриптовые языки ни прямо, ни косвенно не говорят: была произведена замена или нет (не относится к современному JavaScript - там пишется LastIndex в объект RegExp). Костыльное решение этого вопроса - в качестве аргумента замены использовать не строку, а функцию:
Код:
n=0; 'abcba'.replace(/b/g, function() {n++; return ('B')});
в PoSh это завезли только в версии 6.1:
Код:
$n=@{value = 0}; 'abcba' -replace 'b', { $n.value++; 'B' }
либо в более ранних PoSh использовать .NET класс:
Код:
$n=@{value = 0}; [Regex]::Replace('abcba', 'b', { $n.value++ ; 'B' });
(в нашем конкретном случае счётчик не нужен, достаточно булевого флага: была_замена/не_было)
Цитата:
Цитата YuS_2
В общем, если есть какие-либо дополнения по поводу эффективности, хотелось бы увидеть пояснения на примерах, от автора слов:
Цитата Busla:
не надеяться на достаточный объём памяти, а работать построчно
тогда и вопрос перезаписи снимется »
|
я о том, что если в память не лезет, то нам надо писать во временный файл, и результат у нас уже присутсвует на диске. Поэтому оригинальный файл переименовывается в .bak, а временный получает имя основного. И так оно как бы правильнее. Вопрос в итоге чисто декоративный, в плане ресурсов бесплатный.
Эффективность считывания в память будет заметна только для определённого диапазона размеров: для мелких незаметно, в случае крупных - ОС всё равно задействует файл подкачки для освобождения оперативки, и мы возвращаемся к медленным дисковым операциям.
И да, я осознаю, что блочные дисковые операции будут значительно быстрее, но такая оптимизация на мой взгляд нужна скорее для завершённых утилит, а не для скиптов, которые должно быть легко понять и поправить.
|