Performancediskussionen

  • Hallo,

    ich denke, diese Performancediskussion ist im Hilfeforum nicht richtig untergebracht. Und weil sich mir kein besserer Platz aufgedrängt hat, geht es jetzt hier weiter (wenn jemand mit ausreichenden Rechten meint, das gehöre an einen anderen Ort, bitte verschieben).

    Nach dem oben verlinkten Beitrag von AspirinJunkie habe ich selbst noch einmal Alles gecheckt. Wie AU3s StringInStr() kann auch AHKs InStr() in drei verschiedenen Modi arbeiten:

    • case-sensitive (1)
    • case-insensitive (2)
    • case-insensitive-locale (0)

    Ich habe deshalb die Testskripte so abgeändert, dass sie nacheinander alle drei Modi verwenden.

    AHK
    AU3
    [autoit]

    $RunTime = TimerInit()

    [/autoit] [autoit][/autoit] [autoit]

    $Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    $aChars = StringSplit($Chars, "", 2)
    $Len = StringLen($Chars)
    $String = @CRLF

    [/autoit] [autoit][/autoit] [autoit]

    For $I = 0 To $Len - 1
    For $J = 0 To $Len -1
    For $K = 0 To $Len - 1
    $String &= $aChars[$I] & $aChars[$J] & $aChars[$K] & @CRLF
    Next
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Find = "ZAB"

    [/autoit] [autoit][/autoit] [autoit]

    $Loops = 1000
    $T1 = 0
    $T2 = 0
    $T3 = 0

    [/autoit] [autoit][/autoit] [autoit]

    For $C = 1 To $Loops
    $T = TimerInit()
    $Index = StringInStr($String, @CRLF & $Find & @CRLF, 2)
    $T1 += TimerDiff($T)
    $M1 = StringMid($String, $Index + 2, StringLen($Find))
    $T = TimerInit()
    $Index = StringInStr($String, @CRLF & $Find & @CRLF, 1)
    $T2 += TimerDiff($T)
    $M2 = StringMid($String, $Index + 2, StringLen($Find))
    $T = TimerInit()
    $Index = StringInStr($String, @CRLF & $Find & @CRLF, 0)
    $T3 += TimerDiff($T)
    $M3 = StringMid($String, $Index + 2, StringLen($Find))
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $RunTime = TimerDiff($RunTime)
    MsgBox(0, "AU3-Ergebnis für StringInStr():", _
    "Durchschnittliche Ausführungszeit bei " & $Loops & " Aufrufen: " & @CRLF & @CRLF & _
    "CaseSense 2: " & ($T1 / $Loops) & " ms - Treffer: " & $M1 & @CRLF & _
    "CaseSense 1: " & ($T2 / $Loops) & " ms - Treffer: " & $M2 & @CRLF & _
    "CaseSense 0: " & ($T3 / $Loops) & " ms - Treffer: " & $M3 & @CRLF & @CRLF & _
    "Gesamtlaufzeit: " & Round($RunTime) & " ms")

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit]


    Damit die Ergebnisse vergleichbarer sind, habe ich die Zeitmessung in AHK in eine UDF verlagert. Als Ausgleich für den dadurch entstehenden Overhead läuft das Skript jetzt ungebremst.

    Die Ergebnisse dieser Testreihen sind für mich einigermaßen überraschend, hier folgen zwei tendenziell zutreffende Ergebnisse:


    Dass der case-sensitive Vergleich in beiden Sprachen der schnellste ist, wundert mich nicht. Dass allerdings der Abstand zwischen case-insensitive und case-insensitive-locale in AHK deutlich größer ausfällt, hätte ich nicht erwartet. Dass in AU3 case-insensitive mehr Zeit benötigt als case-insensitive-locale, ist für mich aber überhaupt nicht nachvollziehbar. In der AHK-Hilfe steht zum Thema case-insensitive-locale: "(Locale is 1 to 8 times slower than Off depending on the nature of the strings being compared)". Vielleicht gibt es stärkere Schwankungen der Laufzeit abhängig vom Inhalt der Strings, möglicherweise auch in AU3.

    Fazit:

    • Die case-sensitive Suche ist in beiden Sprachen recht gut gelöst. Der Faktor von 4 - 4,5 zu Ungunsten von AU3 zeigt aber, dass noch etwas machbar wäre.
    • Die case-insensitive Suche scheint in AU3 im Vergleich mit AHK und auch im Vergleich mit case-insensitive-locale bemerkenswert schlecht umgesetzt zu sein.
    • Die case-insensitive-locale Suche ist (zumindest für diesen speziellen Fall) in AU3 im Vergleich zu AHK recht gut gelöst. Der Nachteil schmilzt auf einen Faktor von ~ 2.


    Der These, dass AHK schneller sein muss, weil AU3 den umfangreicheren Interpreter hat, kann ich mich nicht anschließen. Die klare Sprachstruktur von AU3 sollte eher ein Vorteil sein. Ich bin allerdings auch der Meinung, dass die Entwickler auf Performancemängel angesprochen werden sollten, fühle mich aber nicht berufen, das selbst zu tun.

  • Hier nochmal meine beiden Testskripte (Sorry wenn das AHK-Skript bisschen merkwürdig aussehen sollte - hab noch nichts mit AHK bisher gemacht):

    Messskripte
    AHK
    AU3
    [autoit]

    $Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    $aChars = StringSplit($Chars, "", 2)
    $Len = StringLen($Chars)
    $String = @CRLF

    [/autoit] [autoit][/autoit] [autoit]

    For $I = 0 To $Len - 1
    For $J = 0 To $Len - 1
    For $K = 0 To $Len - 1
    $String &= $aChars[$I] & $aChars[$J] & $aChars[$K] & @CRLF
    Next
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Find = "ZAB"

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $N = 10000, $iT0, $iT1, $iT2

    [/autoit] [autoit][/autoit] [autoit]

    ;Zeitdauer der For-Schleife bestimmen welche in der Zeitmessung mitwirkt
    $iTFor = TimerInit()
    For $i = 1 To $N

    [/autoit] [autoit][/autoit] [autoit]

    Next
    $iTFor = TimerDiff($iTFor)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Messung mit Parameter 0
    $iT0 = TimerInit()
    For $I = 1 To $N
    StringInStr($String, $Find, 0)
    Next
    $iT0 = (TimerDiff($iT0) - $iTFor) / $N
    ConsoleWrite("StringInStr(,,0): " & Round($iT0, 3) & "ms" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ; Messung mit Parameter 1
    $iT1 = TimerInit()
    For $I = 1 To $N
    StringInStr($String, $Find, 1)
    Next
    $iT1 = (TimerDiff($iT1) - $iTFor) / $N
    ConsoleWrite("StringInStr(,,1): " & Round($iT1, 3) & "ms" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ; Messung mit Parameter 2
    $iT2 = TimerInit()
    For $i = 1 To $N
    StringInStr($String, $Find, 2)
    Next
    $iT2 = (TimerDiff($iT2) - $iTFor) / $N
    ConsoleWrite("StringInStr(,,2): " & Round($iT2, 3) & "ms" & @CRLF)

    [/autoit]


    Hiermit komme ich dann auf folgende Ergebnisse (diesmal auf meinem Thinkpad):

    Messergebnisse
    Code
    ------- AHK -----------------
    CaseSense Off:		0.358  ms
    CaseSense On:		0.142  ms
    CaseSense Locale:	3.944  ms
    
    
    -------- AU3 ------------------------------
    StringInStr(,,0)(CaseSense Off)	: 22.687 ms
    StringInStr(,,1)(CaseSense On)	: 0.712  ms
    StringInStr(,,2)(CaseSense Off)	: 10.876 ms


    Ich konnte deine Ergebnisse also unabhängig nachvollziehen und deine Fazits mittragen.

    Zitat

    Dass in AU3 case-insensitive mehr Zeit benötigt als case-insensitive-locale, ist für mich aber überhaupt nicht nachvollziehbar.

    Der einzige Punkt den ich bei mir nicht reproduzieren konnte.

    Zitat

    Der These, dass AHK schneller sein muss, weil AU3 den umfangreicheren Interpreter hat, kann ich mich nicht anschließen. Die klare Sprachstruktur von AU3 sollte eher ein Vorteil sein.

    Nun für den Mensch mag die Sprachstruktur klarer sein - für die Maschine muss es das nicht.
    AutoIt muss auch ein vielfaches mehr an Funktionen nachschlagen weil der Umfang deutlich größer ist.
    Allerdings möchte ich mich hier nicht zu weit aus dem Fenster lehnen da ich selbst keine Interpreter programmiere ( ;) ).
    Ich weiß es schlicht und ergreifend nicht und kann daher nur Mutmaßungen anstellen was mir als Begründung alles logisch erscheint.

  • Der Unterschied im Case-Sensitiven vergleich lässt sich eventuell noch über den Sprachumfang und die Sprachstruktur zu erklären sein. Dass jedoch der Case-Insentive Vergleich bei AutoIt um einige Sekunden länger dauert als bei AHK, das kann meiner Meinung nach nur an einer schlechteren Umsetzung liegen, denke ich.

  • Wie meinst du das die Unterschiede bei den Case-Sensitive und Case-InSensitive vom Sprachumfang herkommen?
    Das Case-InSensitive generell langsamer ist als Case-Sensitive ist ja noch vollkommen logisch.
    Bei Case-Sensitive wird einfach nur Buchstabe für Buchstabe verglichen ob es der selbe ist.
    Bei Case-Insensitive muss zusätzlich bei jedem Buchstaben nachgeschlagen werden was der entsprechende Groß bzw. Kleinbuchstabe dazu ist.
    Wie du sagtest dass der extreme Unterschied der Case-Insensitive-Suche zwischen AHK und AU3 von einer schlechten Implementierung dieser herrührt haben wir auch schon vermutet und dies scheint ja auch ziemlich offensichtlich.
    Interessant ist allerdings eher die Frage ob der generelle Unterschied zwischen AHK und AU3 eher an der speziellen Implementierung der StringSuch-Funktionen liegt oder direkt an den jeweiligen Interpretern.

  • Zitat
    Dass in AU3 case-insensitive mehr Zeit benötigt als case-insensitive-locale, ist für mich aber überhaupt nicht nachvollziehbar.

    Der einzige Punkt den ich bei mir nicht reproduzieren konnte.

    Hallo AspirinJunkie,

    das habe ich jetzt auch noch mal gecheckt, und siehe da, die von mir eingestellten Ergebnisse gelten nur unter WinXPSP3 mit max 1 GB RAM! Unter Vista und 3 GB Ram ist Modus 2 schneller als Modus 0! Verstehen kann ich das allerdings nicht! ?(

    Nun für den Mensch mag die Sprachstruktur klarer sein - für die Maschine muss es das nicht.


    Der Maschine ist es allerdings völlig egal, dem Interpreter sollte es aber weniger egal sein. ;)