CPU effektiver bei Script Ausführung einsetzten

  • Hallo Leute,

    ich hab eine text datei, die mit 10mio. zufallszeichen beschrieben wird. Jetzt ist es allerdings so, dass dieser Prozess sehr lange dauert, da nur eine CPU verwendet wird und diese auch nur zu max. 25% ausgelastet wird.
    Gibt es eine Möglichkeit, dass das Ganze schneller abläuft, ohne die Zeichenanzahl senken zu müssen?


    Viele Grüße,
    MadCatz

  • Um die Performance zu steigern kannst du
    1a) immer nur einen großen Zufallsblock in die Datei schreiben.
    1b) den Block in einer Struct mit fixer Größe erstellen

    War bei mir um bis zu 9x schneller.

  • @MadCatz, hänge mal dein Script an, damit man überhaupt profilen kann, was "sehr lange dauert".
    Das speichern der Datei jedenfalls nicht, das dauert nur einige Millisekunden...

  • Hi, hier der ScriptPart :)

    Schreibe die Datei mit 4 (oder mehr) Skripten gleichzeitig. Also jeweils ein Viertel der erforderlichen Zeichen in eine Datei und am Ende fügst du die Dateien zusammen.

    da hat ich schon drangedacht, es aber wieder aus verschiedenen Gründen verworfen.

  • Ohne auf die grundlegende Arbeit der Funktion einzugehen, würde ich schätzen/raten das die Aktualisierung der GUI (GUICtrlSetData) mehr Zeit benötigt wie der restliche Teil !

    Ggf. würde ich die Progressbar nur aktualisieren, wenn sich der zu setzende Wert geändert hat.
    z.B.:

    AutoIt
    $new_perc = Int($perc * $i)
    If $new_perc <> $old_perc Then
    	GUICtrlSetData($pb_Progress,....)
    	$old_perc = $new_perc
    EndIf

    Statt 10Mio Änderungen nur noch 100 !

    Anschließend würde ich mir die 10Mio mal durchlaufende, ziemlich komplexe If...ElseIf-Anweisung anschauen. Die wird bei jedem Durchlauf geprüft und ich könnte mit vorstellen, das die mehrfache Prüfung der If-Anweisung doch schon etwas an Zeit verbraucht...

    Zur Nutzung dieses Forum's, ist ein Übersetzer für folgende Begriffe unerlässlich:

    "On-Bort, weier, verscheiden, schädliges, Butten steyling, näckstet, Parr, Porblem, scripe, Kompletenz, harken, manuel zu extramieren, geckukt, würglich, excell, acces oder Compilevorgeng"

    Einmal editiert, zuletzt von Micha_he (29. Februar 2016 um 14:44)

  • bei solchen Spielereien:

    Code
    $posRandomName = Random($int*0.1,$int*0.9,1)
    			Do
    				$posRandomTimer = Random($int*0.1,$int*0.9,1)
    			Until $posRandomName <> $posRandomTimer

    braucht man sich nicht wundern, daß das Skript zwar eine CPU 100% auslastet aber trotzdem schläft.

  • AutoIt
    ElseIf $i = $int*1.00 then

    und mir erschließt sich auch nicht der Grund, warum man einen festen Integerwert unendlich mal mit 1.00 multipliziert ?

    Zur Nutzung dieses Forum's, ist ein Übersetzer für folgende Begriffe unerlässlich:

    "On-Bort, weier, verscheiden, schädliges, Butten steyling, näckstet, Parr, Porblem, scripe, Kompletenz, harken, manuel zu extramieren, geckukt, würglich, excell, acces oder Compilevorgeng"

    • Offizieller Beitrag

    Genau! Die For...Next-Schleife muss so wenig Befehle wie möglich enthalten. Jeder einzelne Befehl in dieser Schleife wird 10.000.000 mal ausgeführt.
    Und solche komplexen If-Anweisungen sind da sehr rechenintensiv.
    Hier mal ein Beispiel, wie das schonmal sehr viel schneller geht:

    Aber wahrscheinlich kontert Andy gleich mit einer Assembler-Variante. :D

  • Aber wahrscheinlich kontert Andy gleich mit einer Assembler-Variante.

    Gerade heimgekommen, Laptop aufgeklappt, F5 gedrückt, die Antworten seit meinem letzten Post gelesen, mittendrin an Assembler gedacht.... 8o

    Die Frage ist, @MadCatz, wo willst du hin, bzw. für was brauchst du bei jedem Scriptdurchlauf 10 Millionen unterschiedlicher Zeichen? Würde es reichen den String nur einmal zu erstellen und dann bspw, 1000erweise Zeichen per "Zufall" zu XORen? Das würde die Anzahl der benötigten Zufallszahlen auf 0,1% drücken!

    @Oscar, ich hatte schon an Assembler gedacht, allerdings steckt mir der Zufallsalgorithmus etwas im Bauch. Natürlich könnte man per

    CryptGenRandom() https://msdn.microsoft.com/de-de/library/…2(v=vs.85).aspx
    oder
    RtlRandomEx() https://msdn.microsoft.com/en-us/library/…1(v=vs.85).aspx
    Zufallszahlen erzeugen. das bissl Bitgeschiebe um daraus den gewünschten Bereich auszufiltern ist Geschwindigkeitstechnisch nur pillepalle.

    Irgendetwas wird ja mit dem Zufalls-String gemacht werden müssen, ggf. ist es besser/schneller, die Zufalls"zeichen" erst später zur Laufzeit zu generieren... :Glaskugel:

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    4 Mal editiert, zuletzt von Andy (29. Februar 2016 um 20:51)

  • Das Skript und die Beschreibung aus dem Eröffnungsbeitrag passen nicht zueinander. Vor allem scheint die gepostete Funktion eine Encryption-Mehode zu sein, siehe

    Code
    GUICtrlSetData($lb_Progress,"Encrypt: Please wait... " & $new_perc & "%")


    Mein alter Kopf ist allerdings noch nicht dahintergekommen wie sie funktionieren soll. :/
    Aber für encrypt gibt es ja schon _Crypt_EncryptData.

    Hier eine Methode die dem Eröffnungsbeitrag entspricht:

    Mein Netbook braucht dafür keine Sekunde. Diesen zufälligen Text auch noch zu encrypten erschien mir unnötig. Eine Fortschrittsanzeige würde mehr Laufzeit verschwenden als das Skript benötigt, also auch weggelassen.
    Übrigens anders als beim Skript des TE's werden die Daten wirklich in eine Datei geschrieben.

    3 Mal editiert, zuletzt von autoBert (29. Februar 2016 um 21:48)

  • @autoBert, dein Script schreibt einfach nur hundert mal dieselben hunderttausend Zeichen nacheinander in die Datei, das ist etwas anderes als 10Millionen zufälliger Zeichen.

    Als Anwendung zum Verschlüsseln ist XOR mit einem Einmalschlüssel OTP https://de.wikipedia.org/wiki/One-Time-Pad geeignet.
    Je länger der (zufällige) Schlüssel, desto sicherer. Wenn der zufällige Schlüssel mindestens so lang ist wie die Nachricht, dann ist diese Verschlüsselung nicht zu brechen.
    Ich vermute, darauf läuft es beim TE hinaus...

  • Wenn ich die 1. Schleife auf 10 Mio setze und dafür die 2. weglasse benötigt mein NetBook 50 Sekunden, davon 30 mSek zum schreiben. Eine Progressbar marquee würde da schon Sinn machen.

  • Ja, ca. 50 Sekunden braucht das AutoIt-Script auf meinem Laptop auch.
    Mal sehen, wieviel schneller diese Aufgabe von einem Compiler/Assembler gelöst werden kann, ich habe ehrlich gesagt keine Ahnung, wieviele Takte RtlRandomEx verbrät.
    Zzt. suche ich noch eine (schnelle!) Lösung, um von dem zufälligen 32-Bit-Wert auf den gesuchten Wertebereich 0-94 (33 bis 127) zu kommen.

    • Offizieller Beitrag

    Neulich hatte ich in C (für Arduino) eine Funktion "map" gelernt und diese in AutoIt umgesetzt:

    AutoIt
    $x = 1294967293
    $y = _Map($x, 0, 4294967296, 33, 127)
    ConsoleWrite($y & @CR)
    
    
    Func _Map($x, $in_min, $in_max, $out_min, $out_max)
    	Return Int(($x - $in_min) * ($out_max - $out_min) / ($in_max - $in_min) + $out_min)
    EndFunc

    Mit dieser Funktion kann man einen Wert aus einem bestimmten Wertebereich in einen anderen Wertebereich umrechnen.
    Ich weiß jetzt aber nicht, wie schnell diese Berechnung in Assembler ist.

  • Ok ok ok, mit der fülle an Antworten hätte ich nicht gerechnet, daher werd ich nicht auf alle eingehen können, ich denke, dass ihr mir das verzeihen werdet :)


    Ohne auf die grundlegende Arbeit der Funktion einzugehen, würde ich schätzen/raten das die Aktualisierung der GUI (GUICtrlSetData) mehr Zeit benötigt wie der restliche Teil !

    Ggf. würde ich die Progressbar nur aktualisieren, wenn sich der zu setzende Wert geändert hat.
    z.B.:

    AutoIt
    $new_perc = Int($perc * $i)
    If $new_perc <> $old_perc Then
    	GUICtrlSetData($pb_Progress,....)
    	$old_perc = $new_perc
    EndIf

    Statt 10Mio Änderungen nur noch 100 !

    Anschließend würde ich mir die 10Mio mal durchlaufende, ziemlich komplexe If...ElseIf-Anweisung anschauen. Die wird bei jedem Durchlauf geprüft und ich könnte mit vorstellen, das die mehrfache Prüfung der If-Anweisung doch schon etwas an Zeit verbraucht...


    Die Prozentzahl wird in meiner Forschleife berechnet, wenn sie 5% weiter ist, wird die Progressbar geändert, allerdings da es in der Forschleife steht, kann ich mir natürlch schwer vorstellne, dass hier die dauer ist, da hier ja nach jedem Zeichen bestimmt wird, ob eine Variante zutrifft.


    bei solchen Spielereien:

    Code
    $posRandomName = Random($int*0.1,$int*0.9,1)
    			Do
    				$posRandomTimer = Random($int*0.1,$int*0.9,1)
    			Until $posRandomName <> $posRandomTimer

    braucht man sich nicht wundern, daß das Skript zwar eine CPU 100% auslastet aber trotzdem schläft.

    Die CPu steht nie bei 100% sie tümpelt max. bei 25% rum und zwatr auf einem Kern, nicht 25% verteilt auf allen 8 Kernen.

    Genau! Die For...Next-Schleife muss so wenig Befehle wie möglich enthalten. Jeder einzelne Befehl in dieser Schleife wird 10.000.000 mal ausgeführt.
    Und solche komplexen If-Anweisungen sind da sehr rechenintensiv.
    Hier mal ein Beispiel, wie das schonmal sehr viel schneller geht:

    Aber wahrscheinlich kontert Andy gleich mit einer Assembler-Variante. :D

    Das lässt mich jetzt schlussfolgern, dass ich mehrere Forschleifen unterienander in die Funktion packe, nach Beendigung einer Schleife den String sichere, die Progressbar anpasse und die nächste Schleife abgehe, sollte schneller sein, wird gleich ausprobiert.

    Das Skript und die Beschreibung aus dem Eröffnungsbeitrag passen nicht zueinander. Vor allem scheint die gepostete Funktion eine Encryption-Mehode zu sein, siehe

    Code
    GUICtrlSetData($lb_Progress,"Encrypt: Please wait... " & $new_perc & "%")

    Mein alter Kopf ist allerdings noch nicht dahintergekommen wie sie funktionieren soll. :/
    Aber für encrypt gibt es ja schon _Crypt_EncryptData.

    Hier eine Methode die dem Eröffnungsbeitrag entspricht:

    Mein Netbook braucht dafür keine Sekunde. Diesen zufälligen Text auch noch zu encrypten erschien mir unnötig. Eine Fortschrittsanzeige würde mehr Laufzeit verschwenden als das Skript benötigt, also auch weggelassen.
    Übrigens anders als beim Skript des TE's werden die Daten wirklich in eine Datei geschrieben.

    Ja das ganze hat was mit Encryption zutun, allerdings wird die erzeugte Datei, die mit 10Mio. Zufallszeichen beschrieben wird erst am Ende richtig mit 256bit aes und einem Zufallskennwort mit 256bit verschlüsselt.
    Da das ganze bei 100% so schnell geht, hab ich den Text mit "Encrypt: Succesfull..." in die Funktion gepackt.


    So also ich teste jetzt mal das ganze mit mehrenen Forschleifen und werde berichten. :thumbup:

    Ich dnake euch schonmal

  • @Oscar
    Müsste $in_max nicht 4294967295 lauten?
    Die Rechnung könnte man ja noch aufgrund der konstanten Parameter auf Return 94/4294967295 * $x + 33 eindampfen.
    Könnte mir aber vorstellen, dass das hin und hergerechne zwischen Int und Float in Assembler dabei ekelhaft werden könnte.


    Eventuell könnte es schneller sein von einer einfachen Grundrechnung auszugehen und im Sonderfall einfach eine neue Zufallszahl zu erzeugen anstatt die alte krumm zu biegen.
    Also vielleicht so:

    AutoIt
    For $i = 1 To 1000
    	$y = Random(0, 2147483647, 1)
    	$x = BitAND($y, 127); alles über 127 abschneiden
    	While $x < 33
    		$y = Random(0, 2147483647, 1)
    		$x = BitAND($y, 127)
    	WEnd
    	ConsoleWrite($x & @CRLF)
    Next

    Einmal editiert, zuletzt von AspirinJunkie (1. März 2016 um 10:59) aus folgendem Grund: Sonderfall des Zahlenbereiches für AutoIt-Random bei Integerzahlen beachtet.

  • So hab es jetzt so gelöst:

    Das ganze ist jetzt von knapp 2min auf max 15sek. gefallen, die CPu tümpelt aber immer noch bei 25% :D

    Also war überaus erfolgreich! :party: Manchmal braucht man einfach nur ein paar Leute die einem den entscheidenden Denkanstoß geben :)

    Ich danke euch vielmals für eure super Hilfe :thumbup:

    • Offizieller Beitrag

    Müsste $in_max nicht 4294967295 lauten?

    Ja klar: 2 ^ 32 - 1 :rolleyes:
    Blöder Fehler!

    Edit: Um die Rechnung in Assembler zu vereinfachen, wäre es natürlich besser, wenn der gesamte ASCII-Zeichensatz genutzt würde. Dann könnte man die Zufallszahl einfach "shiften":

    AutoIt
    $iRandom = Random(0, 2^31-1, 1)
    ConsoleWrite($iRandom & @CR)
    $iRandom = BitShift($iRandom, 23)
    ConsoleWrite($iRandom & @CR)