2012-01-17 9 views
6

W jaki sposób wydajność tych dwóch sposobów określania, czy ciąg rozpoczyna się od określonego podciągu w Delphi, porównuje? Czy jeden jest znacznie szybszy/bardziej wydajny od drugiego?Efektywność technik "zaczyna z podciąganiu" w Delphi?

if ((testString[1] = '=') AND (testString[2] = '?')) then ... 

vs.

if (AnsiStartsStr('=?', testString)) then ... 
+4

Ewaluacja od lewej do prawej strony nie jest wymagane do pierwszej metody. Możesz go najpierw dostosować, aby odfiltrować najmniej częste wystąpienia. Na przykład możesz najpierw przetestować znak zapytania, jeśli jest on rzadszy. –

Odpowiedz

7

Cóż, pierwszy będzie zdecydowanie szybciej. Rozwiązywanie zakamuflowanego, bardzo specyficznego problemu prawie zawsze przebiega o wiele szybciej, niż przekazywanie określonego rozwiązania do rutynowych czynności rozwiązywania problemów ogólnych. Jeśli chodzi o "znacznie" szybciej, dlaczego go nie przetestujesz? Uruchom obie wersje w pętli 10 milionów razy i użyj TStopwatch (lub czegoś innego, jeśli nie masz D2010 lub nowszego), aby to zrobić.

Jedna rzecz: pierwsza jest zdecydowanie szybsza, ale może być również błędna. Jeśli nie zostanie zagwarantowane, że length(TestString) ma wartość> = 2, może wystąpić tutaj warunek błędu. Jeśli TestString jest pustym łańcuchem, spowoduje to zgłoszenie wyjątku. Jeśli nie, możesz uzyskać wyjątek lub nie, w zależności od ustawień kompilatora.

+2

Dobra uwaga. Pierwszy nie zawsze jest bezpieczny. To przynajmniej potrzebuje 'if Length (testString)> = 2) i ...' –

+1

Ocena zwarcia ORAZ również stanowi dużą pomoc w przypadkach, gdy nie pasuje. –

+0

@MarcusAdams Jeśli zaniedbałeś aspekt LOCALE 'AnsiStartsStr', to' AnsiStartsStr' może być zaimplementowane tak samo wydajnie jak jawne 'if' (chociaż prawie na pewno nie jest) –

2

Pierwszy w oknie CPU jest tylko mov, cmp i jnz (ewentualnie powtórzone jeden raz), podczas gdy druga jest o wiele bardziej skomplikowany (używa Copy i WinApi na CompareString). Najpierw powinien być szybszy.

+0

'AnsiStartsStr()' używając 'Copy()' wewnętrznie jest złym wdrożeniem w części Borland, IMHO. Mogli użyć 'CompareString()' bez 'Copy()' jak 'AnsiStartsText()', wystarczy wywołać 'CompareString()' z różnymi flagami. Szkoda, że ​​CodeGear i Embarcadero nigdy nie naprawili tego przez lata po tym, jak Borland zrezygnował z posiadania narzędzi programistycznych. –

+0

@ RemyLebeau-TeamB Główne wąskie gardło 'AnsiStartsStr' nie jest wewnętrznym użyciem' copy', ale użycie 'AnsiSameStr', które wywołuje bardzo wolny interfejs' CompareString' Windows API. W rzeczywistości większość funkcji 'Ansi *' wywołuje te interfejsy API i jest powolna, jeśli obsługa całego Unicode nie jest konieczna (np. Przy użyciu znaków 7-bitowych Ascii, co często ma miejsce w programowaniu). Cały RTL jest pełen działającego kodu, ale nie jest napisany dla szybkości. Moją ulubioną jest implementacja "IntToStr", która jest po prostu cholernie powolna (nawet wolniejsza od Delphi 2009). –

4

Jeśli potrzebujesz szybkość z elastycznością można spróbować coś takiego:

function StatsWith(const SubStr, Str: string): Boolean; inline; 
begin 
    if Length(SubStr) <= Length(Str) then 
    Result := CompareMem(Pointer(SubStr), Pointer(Str), ByteLength(SubStr)) 
    else 
    Result := False; 
end; 
+0

ByteLength() będzie działać z Delphi 2009+ tylko podejrzewam. 'length (SubStr) * sizeof (char)' jest bardziej standardowy. –

+1

@ArnaudBouchez Jeśli nie masz zamiaru obsługiwać starych wersji kompilatora, "ByteLength" jest bardziej przejrzyste. –

+0

Bajtowa długość jest zaimplementowana (w D2010) jako funkcja wbudowana, która jest zaimplementowana jako 'Długość (s) * RozmiarOf (Char)' ... W każdym razie, może to być przesada, ale prawdopodobnie użyłbym 'Długość (s) * StringElementSize (s) '. –

Powiązane problemy