1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Andy

Beiträge von Andy

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 21. März 2016 um 23:50
    Zitat von AspirinJunkie

    Wenn die Kodierung außer Acht gelassen wird und nur Byteweise nach 0D oder 0A gesucht wird werden so diese fälschlicherweise als Zeilenende erkannt.

    Da haben wir klassisch aneinander vorbeigeredet :D
    010D enthält ein Zeichen, welches im ASCII-Bereich als Steuerzeichen gilt. Enthält ein Text (!) Dateiinhalt solch ein Zeichen, dann ist dieser UTF8-kodiert, wenn 000D auch UTF16.
    Genau daher müssen diese Inhalte analysiert werden, um die Kodierungen zu erkennen.
    Im ASM-Code habe ich es mir einfach gemacht und nur nach einem Zeichen gesucht. Ob CR oder LF ist unerheblich, man könnte auch die Anzahl aller "e" ermitteln.(letzter Parameter im DllCallAddress).
    Man könnte den Code noch dahingehend erweitern, erst nach allen Zeichen unterhalb ASCII 31 zu schauen, wenn solch ein Zeichen vorkommt, dann "könnte" eine UTF8/16-Kodierung vorliegen und dann müsste entsprechend ausgewertet werden. Aber wer sagt, dass nicht eine EXE-Datei in eine Textdatei umbenannt wurde....
    Lade mal eine ausführbare Datei in Scite, dann weißt du, worauf ich (nicht :P ) hinaus will!


    Zitat von Andy

    Ich werde mal gesamte Verzeichnisse einlesen, bei hunderten unterschiedlicher Dateien sollte sich ein plausibler Mittelwert ergeben.

    Naja, mit den 100MB/s hab ich nicht mal schlecht geschätzt.
    Ich habe meinen "C:\"-Ordner rekursiv durchsucht aber nur alle Dateien zwischen 60 und 400MB eingelesen. Dabei sind interessante Sachen herausgekommen.
    Es gibt definitiv von Windows gecachte bzw. im Arbeitsspeicher stehende Dateien, diese haben bei Größen um die 330MB nur Lesezeiten im Millisekundenbereich, da wurde seitens System (ReadFile) einfach nur der Speicher gemapped, was zu "Leseraten" von 1GB/s führt. Das ist im Speichertransfer realistisch.
    Dann gibt es Dateien, die haben 80 bis 100MB und werden in einer Sekunde eingelesen, auch realistische Transferzeiten von 80 bis 100MB/s.
    Der überwiegende Teil der Dateien bewegt sich bei ca. 30-90MB/s. Im Schnitt erreiche ich 66MB/s.
    Bei "kaltem" Rechner, also direkt nach dem Aufwachen aus dem Schlafmodus und niedriger Prozessor/Platten-Temperatur erreiche ich bei sonst gleichen Voraussetzungen 88 MB/s...das sind Abweichungen von 20-30%!!!!

    Um nicht den schon angesprochenen "AutoIt-Speicher-Schiebe-Malus" einzurechnen, habe ich nur die reinen Transferzeiten von "Platte" nach "RAM" ermittelt (s. auskommentiertes Return in _TextFileRead() ).
    AspirinJunkies _FileReadFast() gibt auch Strings zurück, daher dauerts auch so lange...
    Wer mag, kann ja mal AspirinJunkies Funktion mit AutoIt-FileRead vergleichen.... :theke:

    AutoIt
    #include <Array.au3>
    #include <WinAPI.au3>
    
    
    Global $kerneldll = DllOpen("kernel32.dll")
    
    
    
    
    $files = _GetFilesFolder_Rekursiv("c:\", "*", 0, 0)
    
    
    ;_ArrayDisplay($files)
    
    
    $gesamt_mb = 0
    $gesamt_s = 0
    
    
    
    
    For $i = 1 To UBound($files) - 1
        $size = FileGetSize($files[$i])
        If $size > 60e6 And $size < 400e6 Then                ;>100 und kleiner 800MB
            $t = TimerInit()
            ;$data = _FileReadFast($files[$i])   ;incl. Rückgabe als string
            $data = _TextFileRead($files[$i])                 ;excl. Rückgabe als String
            $m = TimerDiff($t)
            $len = $size                                      ;StringLen($data)
    
    
            $MB = Int($len / 1e6)                             ;Megabytes
            $s = Int($m) / 1000                               ;Sekunden
            $MBS = Int($MB / $s)
            $gesamt_mb += $MB
            $gesamt_s += $s
            ConsoleWrite($files[$i] & "       " & Int($len / 1e6) & " MB    $t= " & $s & "s      MB/s: " & $MBS & @CRLF)
        EndIf
    
    
    Next
    $gesamt_mbs = Int($gesamt_mb / $gesamt_s)
    MsgBox(0, 0, $gesamt_mb & " MB gelesen in " & $gesamt_s & " Sekunden => " & $gesamt_mbs & " MB/s")
    
    
    
    
    Func _TextFileRead($filename)
        Local $nbytes
        Local $filesize = FileGetSize($filename)
        Local $filestruct = DllStructCreate("char[" & $filesize & "]")
        Local $filestructptr = DllStructGetPtr($filestruct)
    
    
        Local $hfile = _WinAPI_CreateFile($filename, 2, 2)
        _WinAPI_ReadFileXXX($hfile, $filestructptr, $filesize, $nbytes)
    
    
        _WinAPI_CloseHandle($hfile)
        ;Return DllStructGetData($filestruct, 1)
    
    
    EndFunc                                                   ;==>_TextFileRead
    
    
    
    
    
    
    Func _WinAPI_ReadFileXXX($hfile, $pBuffer, $iToRead, ByRef $iRead, $pOverlapped = 0)
        Local $aResult = DllCall($kerneldll, "bool", "ReadFile", "handle", $hfile, "ptr", $pBuffer, "dword", $iToRead, _
                "dword*", 0, "ptr", $pOverlapped)
        If @error Then Return SetError(@error, @extended, False)
    
    
        $iRead = $aResult[4]
        Return $aResult[0]
    EndFunc                                                   ;==>_WinAPI_ReadFileXXX
    
    
    
    
    ; #FUNCTION#============================================================================================================
    ; Name...........: _FileReadFast
    ; Description ...: Read text or binary files into a variable. Faster than FileRead at big file sizes
    ; Syntax.........: _FileReadFast(Const $s_FilePath, [[Const $flag_Encoding = Default], [Const $flag_FileScan = 2]])
    ; Parameters ....: $s_FilePath - the file path as a string
    ;                  $flag_Encoding: Default = the file encoding is determined by the function
    ;                                  0 = file gets handled as a binary file -> return a binary-variable
    ;                                  other = possible values are the same es the flag parameter of BinaryToString (faster)
    ;                  $flag_FileScan: The mode-parameter of FileGetEncoding $flag_Encoding = Default
    ; Return values .: Success - the file content as a string or a binary-variable
    ;                  Failure - a Null-String and error gets set to:
    ;                      @error = 1: File doesn't exist
    ;                             = 2: Couldn't open file for reading
    ;                             = 3: Couldn't determine file size
    ;                             = 4: error while reading file
    ;                      @extended = WinAPI error code
    ; Author ........: AspirinJunkie
    ; ===============================================================================================================================
    Func _FileReadFast(Const $s_FilePath, Const $flag_Encoding = Default, Const $flag_FileScan = 2)
        If Not FileExists($s_FilePath) Then Return SetError(1, 0, "")
        Local $h_DLL_KERNEL32 = DllOpen("kernel32.dll")
        Local $a_Ret
        $a_Ret = DllCall($h_DLL_KERNEL32, "handle", "CreateFileW", "wstr", $s_FilePath, "dword", 0x80000000, "dword", 1, "struct*", Null, "dword", 3, "dword", 0, "ptr", Null)
        If DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0] Then Return SetError(2, DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0], "")
        Local $h_File = $a_Ret[0]
        $a_Ret = DllCall($h_DLL_KERNEL32, "bool", "GetFileSizeEx", "handle", $h_File, "int64*", 0)
        If DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0] Then Return SetError(3, DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0], "")
        Local $d_Bytes = $a_Ret[2]
        Local $t_Buffer = DllStructCreate("byte[" & $d_Bytes & "]")
        DllCall($h_DLL_KERNEL32, 'bool', 'ReadFile', 'handle', $h_File, 'struct*', $t_Buffer, 'dword', $d_Bytes, 'dword*', 0, 'ptr', 0)
        If DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0] Then Return SetError(4, DllCall($h_DLL_KERNEL32, "dword", "GetLastError")[0], "")
        DllCall($h_DLL_KERNEL32, "bool", "CloseHandle", "handle", $h_File)
        DllClose($h_DLL_KERNEL32)
        Switch $flag_Encoding
            Case Default                                      ; determine file encoding
                Switch FileGetEncoding($s_FilePath, $flag_FileScan)
                    Case 32, 1024                             ; UTF-16 LE
                        Return BinaryToString(DllStructGetData($t_Buffer, 1), 2)
                    Case 64, 2048                             ; UTF-16 BE
                        Return BinaryToString(DllStructGetData($t_Buffer, 1), 3)
                    Case 128, 256                             ; UTF-8
                        Return BinaryToString(DllStructGetData($t_Buffer, 1), 4)
                    Case 512                                  ; ANSI
                        Return BinaryToString(DllStructGetData($t_Buffer, 1), 1)
                    Case Else                                 ; handle as binary
                        Return DllStructGetData($t_Buffer, 1)
                EndSwitch
            Case 0                                            ; binary file
                Return DllStructGetData($t_Buffer, 1)
            Case Else                                         ; encoding set by user
                Return BinaryToString(DllStructGetData($t_Buffer, 1), $flag_Encoding)
        EndSwitch
    EndFunc                                                   ;==>_FileReadFast
    
    
    
    
    ;==================================================================================================
    ; Function Name:   _GetFilesFolder_Rekursiv($sPath [, $sExt='*' [, $iDir=-1 [, $iRetType=0 ,[$sDelim='0']]]])
    ; Description:     Rekursive Auflistung von Dateien und/oder Ordnern
    ; Parameter(s):    $sPath     der Basispfad für die Auflistung ('.' -aktueller Pfad, '..' -Parentpfad)
    ;                  $sExt      Erweiterung für Dateiauswahl '*' oder -1 für alle (Standard)
    ;                  $iDir      -1 Dateien+Ordner(Standard), 0 nur Dateien, 1 nur Ordner
    ;      optional:   $iRetType  0 gibt Array, 1 gibt String zurück
    ;      optional:   $sDelim    legt Trennzeichen für Stringrückgabe fest
    ;                             0 -@CRLF (Standard)  1 -@CR  2 -@LF  3 -';'  4 -'|'
    ; Return Value(s): Array (Standard) od. String mit den gefundenen Pfaden der Dateien und/oder Ordner
    ;                  Array[0] enthält die Anzahl der gefundenen Dateien/Ordner
    ; Author(s):       BugFix (bugfix@autoit.de)
    ;==================================================================================================
    Func _GetFilesFolder_Rekursiv($sPath, $sExt = '*', $iDir = -1, $iRetType = 0, $sDelim = '0')
        Global $oFSO = ObjCreate('Scripting.FileSystemObject')
        Global $strFiles = ''
        Switch $sDelim
            Case '1'
                $sDelim = @CR
            Case '2'
                $sDelim = @LF
            Case '3'
                $sDelim = '                                   ;'
            Case '4'
                $sDelim = '|'
            Case Else
                $sDelim = @CRLF
        EndSwitch
        If ($iRetType < 0) Or ($iRetType > 1) Then $iRetType = 0
        If $sExt = -1 Then $sExt = '*'
        If ($iDir < -1) Or ($iDir > 1) Then $iDir = -1
        _ShowSubFolders($oFSO.GetFolder($sPath), $sExt, $iDir, $sDelim)
        If $iRetType = 0 Then
            Local $aOut
            $aOut = StringSplit(StringTrimRight($strFiles, StringLen($sDelim)), $sDelim, 1)
            If $aOut[1] = '' Then
                ReDim $aOut[1]
                $aOut[0] = 0
            EndIf
            Return $aOut
        Else
            Return StringTrimRight($strFiles, StringLen($sDelim))
        EndIf
    EndFunc                                                   ;==>_GetFilesFolder_Rekursiv
    
    
    Func _ShowSubFolders($Folder, $Ext = '*', $Dir = -1, $Delim = @CRLF)
        If Not IsDeclared("strFiles") Then Global $strFiles = ''
        If ($Dir = -1) Or ($Dir = 0) Then
            For $file In $Folder.Files
                If $Ext <> '*' Then
                    If StringRight($file.Name, StringLen($Ext)) = $Ext Then _
                            $strFiles &= $file.Path & $Delim
                Else
                    $strFiles &= $file.Path & $Delim
                EndIf
            Next
        EndIf
        For $Subfolder In $Folder.SubFolders
            If ($Dir = -1) Or ($Dir = 1) Then $strFiles &= $Subfolder.Path & '\' & $Delim
            _ShowSubFolders($Subfolder, $Ext, $Dir, $Delim)
        Next
    EndFunc                                                   ;==>_ShowSubFolders
    Alles anzeigen
  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 21. März 2016 um 21:14

    @AspirinJunkie,
    nachdem ich mir deinen Code angeschaut hatte, frage ich mich auch, wieso ich in der ReadFile()-Funktion überhaupt blockweise Daten auslese ;(
    Die komplette Dateigröße hineingeworfen reicht, um ein gutes Ergebnis zu erzielen, der Overhead des Block-Loops fällt somit komplett weg.

    Das Einlesen der 100MB in den Speicher dauert bei mir ca. 100ms, Übertragung aus der Struct in die Variable $string=dllstructgetdata(blablub) dauert EINE SEKUNDE! Die zehnfache Zeit für ein simples memcopy...ohne Worte.
    Irgendetwas innerhalb von AutoIt werkelt da sehr gemächlich, und wahrscheinlich (eher sicher) sind es nicht die API-Funktionen, wie wir hier gezeigt haben.


    Zitat von AspirinJunkie

    Obwohl ich mir da noch unschlüssig bin wie sich die Funktion bei UTF-8 oder anderem verhält.

    Das Problem ist, dass eine Datei grundsätzlich als ASCII eingelesen wird. Erst im Nachhinein wird versucht, durch diverse Verfahren herauszufinden, in welcher Kodierung die "Datei" vorliegt. Es gibt Betriebssysteme, in welchen es eine Dateibeschreibung gibt, in der bspw. stehen würde, dass eine UTF8/16-Kodierung vorliegt. Das hat den immensen Vorteil, die langwierigen "Testverfahren" garnicht erst einsetzen zu müssen.
    UTF8/16 benutzen für EndOfLine 0x000D und/oder 0x000A statt Ascii 0x0D0A (CRLF) , haben also mitten im "Text" zwangsläufig Nullbytes. Sind diese vorhanden, zählt man statt 0x0A eben die 0x000A...

    Zitat von AspirinJunkie

    Plausibel erscheinen mir auf ner alten Notebookfestplatte Einlesezeiten von 78ms für 100mb überhaupt nicht.

    Ja, 100-200MB pro Sekunde sollten eher hinkommen.
    Ich werde mal gesamte Verzeichnisse einlesen, bei hunderten unterschiedlicher Dateien sollte sich ein plausibler Mittelwert ergeben.

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 21. März 2016 um 06:59

    Hi, das Zählen der Zeilen ist mit dem Assemblercode recht schnell erledigt, in deinem Fall sicherlich nur einige Millisekunden...

    AutoIt
    $asmcode = "0x8B7C24048B4C24088B54240C88D6C1E20888F2C1E20888F2660F6EC2660F70C0005583EC1089E3C70300010102C7430401020203C7430801020203C7430C0203030431F631ED660F6FC8660F740C37660FD7D185D2742989D083E00FD701C5C1EA0489D083E00FD701C5C1EA0489D083E00FD701C5C1EA0489D083E00FD701C583C61039CE76BF89E883C4105DC3"
    $codestruct = DllStructCreate("byte[" & StringLen($asmcode) / 2 - 1 & "]") ;speicher für asmcode...
    DllStructSetData($codestruct, 1, $asmcode) ;...mit code füllen


    erstellt einen Speicherbereich und schreibt den Code hinein.

    AutoIt
    $ret = DllCallAddress("uint:cdecl", DllStructGetPtr($codestruct), "ptr", $filestructptr, "uint", $filesize, "dword", 0x0A)
    $nr_lf = $ret[0]  ;Anzahl der LF

    ruft den Code auf und gibt die Anzahl der LF zurück.
    $filestructptr ist der Pointer auf den von "readfile" verwendeten Puffer ( Achtung, Puffer PLUS einmal die Blockgröße! ), $filesize enthält die Dateigröße.

    Ich denke, irgendwer wird diese Zeilen in die _FileReadFast()-Funktion einbauen können und per @extended die Anzahl der LF ausgeben...

    //EDIT
    Dann schreibe ich auch das Pendant in 64-Bit :D

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 19. März 2016 um 14:17

    :thumbup:
    Ja, wird man sicherlich gebrauchen können, ich binde diese Funktion mal testweise in geschwindigkeitskritische Scripte ein.
    Schaumamal, ob man so auch andere "Programmiersprachen" beschleunigen kann bzw. die Dateigrößen dort massiv erweitern kann, ohne an Performance zu verlieren...

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 19. März 2016 um 12:35

    Bei deinem Script stimmt alles! In der Funktion _TextFileRead() steht nicht umsonst das "Text", denn AutoIt(C++)-typisch werden beim Schreiben in einen String (mein Auslesen der Struct) nur Daten bis zum ersten Nullbyte berücksichtigt.
    Ansonsten liegen wir gleichauf^^. Würde AutoIt Pointer unterstützen, wäre das der Faktor 3 im Vergleich zur nativen Funktion!

    Code
    -------- Test mit 10 Durchläufen -------------
    
    
    Methode           : StringReplace MyFileRead
    mittlere Dauer    :   0.9206 s
    Standardabweichung:   0.0148 s
    Minimum           :   0.8795 s
    Maximum           :   0.9322 s
    
    
    Methode           : _TextFileRead
    mittlere Dauer    :   0.9397 s
    Standardabweichung:   0.0098 s
    Minimum           :   0.9312 s
    Maximum           :   0.9590 s
    
    
    Methode           : FileRead
    mittlere Dauer    :   3.5304 s
    Standardabweichung:   0.0064 s
    Minimum           :   3.5208 s
    Maximum           :   3.5430 s
    Alles anzeigen

    Fraglich ist nur, wo die native AutoItfunktion die Zeit verliert. Ich bin ziemlich sicher, dass die DEV´s die C++-Standard-Bibliotheken benutzen...

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 19. März 2016 um 11:40

    Script oben etwas geändert:

    Code
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 1024 bytes    time: 4599 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 8192 bytes    time: 679 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 27648 bytes    time: 282 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 65536 bytes    time: 184 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 128000 bytes    time: 150 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 221184 bytes    time: 136 ms  
    WinAPI:   Read 96MB File    #Lines: 2097152   Blocksize: 351232 bytes    time: 129 ms  
    
    
    Autoit:   Read 96MB File   time: 3616 ms

    Sieht wohl so aus, als ob größere Blockgrößen doch schneller sind...selbst auf meinem langsamen Rechner und AutoIt komme ich in den Bereich der Ergebnisse des TE. Und die kommen aus (hoffentlich) optimierten GNU-Bibliotheken.
    Btw. dauert die Suche nach den LF mit meinem unoptimierten ASM-Code ca. 30ms bei 96MB Dateigröße, das Laden dauert somit 100ms, nicht schlecht....

  • CSV Datei Zeilen zählen - extrem schnell - GNUWin32

    • Andy
    • 19. März 2016 um 03:04
    Zitat von UEZ

    Benötigt für eine 230 mb große CSV Datei ca. 7600 ms, um die Zeilen zu zählen. Built-in ca. 8500 ms. -> kein richtiger Gewinn.

    Naja, profilen hilft^^, und zwar vorher....
    Wenn Fileread() etwa 90% der Zeit braucht, nützt es dir nichts bei den verbleibenden 10% in Beschleunigung zu investieren!
    Dateien werden idR. nicht "am Stück", sondern in Blöcken zu einigen Bytes Größe eingelesen.
    Das AutoIt-native FileRead() arbeitet höchstwahrscheinlich mit Blockgrößen von 2KB oder 4KB. Woher ich das weiß? Weil ich es ausprobiert und verglichen habe.
    Bei kleinen Dateien ist das egal, aber wenn bei großen Dateien Blocks von 64kb gelesen werden, dann beschleunigt sich das Lesen der gesamten Datei in den Speicher um Faktor 3 bis 4.
    Jedenfalls bei meinem Laptop (mit SSD), ihr könnt die Blockgrößen im anliegenden Script gerne variieren.

    Habe mal die Vorgaben von ca. 96MB Dateigröße mit ca. 2Mio Zeilen umgesetzt und bei mir ist eine Blockgröße von 32 bis 64KB optimal...

    Das Suchen von @LF habe ich (wen wundert´s) in Assembler umgesetzt.
    Dazu habe ich ein XMM-Register als 16x 1 Byte(Char) verwendet, dort das Linefeed maskiert und die "Treffer" in ein 16-bit-Register geschrieben. Die Anzahl der gesetzten Bits in diesem Register ist die Anzahl der Linefeed innerhalb der 16 Bytes. Über die verschiedenen "popcount"-Methoden (Zählen von gesetzten Bits innerhalb eines Registers) wurden schon Bücher geschrieben. Div. Methoden hier
    Ich habe, weil ich nur die Handvoll 32-Bit-Register verwenden wollte, eine 16 byte große LookUpTable (LUT) auf dem Stack erstellt und per XLATB-Befehl die Anzahl der gesetzten Bits (nibble von 4 Bits Größe, also nur die untere Hälfte vom AL-Register) ausgelesen. Alle diese ausgelesenen Anzahlen ergeben summiert die Gesamtzahl der LineFeeds im String.
    Geht sicherlich noch schneller, @AspirinJunkie könnte ja mal den ( neuen? ) Intel-Compiler anwerfen 8o . Muster siehe HIER. Habe echt keine Ahnung inwieweit der compilierte Code schneller ist als mein ASM-Pendant, würde mich aber absolut nicht wundern, habe ja auch eine komplett andere Methode angewandt.
    Letztendlich ist es auch schnurz, ob die Anzahl der Linefeeds (oder auch anderer Zeichen) eine Handvoll Millisekunden schneller oder langsamer ist, wenn allein das Lesen des Dateiinhaltes schon 90% der Laufzeit ausmacht...
    Alleine das "kopieren" des Strings in eine Variable dauert sehr lange, also $data=dllstructgetdata(blablub). Da man das für die vorliegende Problemstellung aber garnicht braucht, lässt man es weg...


    Zusammenfassung:
    Bei großen Dateien ist das AutoIt-FileRead() SEHR langsam, schneller ist die gezeigte Methode über _WinAPI_FileRead() mit einer auf das eigene System angepasster Blockgröße.
    Benötigt man den Dateiinhalt nicht in Form einer Variable, ist es sinnvoller/schneller, direkt mit den Daten im Speicher (struct) zu arbeiten.

    Auf meinem Laptop AMD A6-3400M APU with Radeon(tm) HD Graphics @2,3Ghz (Samsung SSD):
    Vergleich Datei laden und die LF zählen:
    WinAPI: Read 96MB File #Lines: 2097152 Blocksize: 65536 bytes time: 214 ms

    AutoIt: Read 96MB File time: 5374 ms OHNE zählen der LF....wobei man fairerweise zugeben muss, daß natürlich die Rückgabe des Dateiinhaltes in einer Variable enthalten ist.

    //EDIT
    Speicherleck entfernt...

    AutoIt
    #include <WinAPI.au3>
    #include <Memory.au3>
    #include <MemoryConstants.au3>
    #include <APIFilesConstants.au3>
    ;~ #include "assembleit2_64.au3"
    
    
    
    
    #cs _crlf
        use32                            ;32 bit
    
    
        mov edi,[esp+4]                  ;adresse string
        mov ecx,[esp+8]                  ;anzahl zeichen
    
    
        mov edx,[esp+12]                 ;ein byte zeichen in alle bytes von edx
        mov dh,dl                        ;0x00000A0A
        shl edx,8                        ;0x000A0A00
        mov dl,dh                        ;0x000A0A0A
        shl edx,8                        ;0x0A0A0A00
        mov dl,dh                        ;0x0A0A0A0A
        movd xmm0,edx
        pshufd xmm0, xmm0, 0x00          ;maske LF, in allen 16 bytes steht das zeichen
    
    
        push ebp                         ;sichern
        sub esp,16                       ;platz für die LUT vom stack reservieren
        mov ebx,esp                      ;ebx  = startadresse der LUT, für XLATB
    
    
        mov dword[ebx],0x02010100        ;16 bytes LUT füllen, little endian... ;-)
        mov dword[ebx+4],0x03020201
        mov dword[ebx+8],0x03020201
        mov dword[ebx+12],0x04030302
    
    
        xor esi,esi                      ;zähler bytes
        xor ebp,ebp                      ;anzahl treffer
    
    
        _loop:
    
    
        movdqa xmm1,xmm0                 ;maske sichern
        PCMPEQB xmm1,[edi+esi]           ;16 bytes nach zeichen durchsuchen
        PMOVMSKB edx,xmm1                ;treffer -> bit =1 in dh/dl
    
    
        test edx,edx                     ;null?
        jz _weiter                       ;nur berechnen, wenn mindestens ein Bit gesetzt ist
    
    
        mov eax,edx                      ;erstes byte
        and eax,0xF                      ;erste 4 bit sind der index für die LUT
        XLATB                            ;al=LUT[al]  summe gesetzter bits
        add ebp,eax                      ;treffer zusammenzählen
    
    
        shr edx,4                        ;nächstes nibble
        mov eax,edx                      ;erstes byte
        and eax,0xF                      ;erste 4 bit
        XLATB                            ;al=LUT[al]  summe
        add ebp,eax                      ;treffer zusammenzählen
    
    
        shr edx,4                        ;nächstes nibble
        mov eax,edx                      ;erstes byte
        and eax,0xF                      ;erste 4 bit
        XLATB                            ;al=LUT[al]  summe
        add ebp,eax                      ;treffer zusammenzählen
    
    
        shr edx,4                        ;nächstes nibble
        mov eax,edx                      ;erstes byte
        and eax,0xF                      ;erste 4 bit
        XLATB                            ;al=LUT[al]  summe
        add ebp,eax                      ;treffer zusammenzählen
    
    
        ;~  _asmdbg_()
        _weiter:
    
    
        add esi,16                       ;nächste 16 bytes
        cmp esi,ecx                      ;ende erreicht?
        jbe _loop                        ;nein, weiter
    
    
        mov eax,ebp                      ;rückgabe=summe aller treffer
        add esp,16                       ;stack wiederherstellen
        pop ebp                          ;restaurieren!
    
    
        ret
    
    
    #ce
    
    
    
    
    Global $kerneldll = DllOpen("kernel32.dll") ;falls jemand die winapi-Funktion ausprobieren will, der zugriff über den handle ist schneller als über den dateinamen
    
    
    
    
    ;Erstellen einer Datei von 96MB und ca 2 Mio Zeilen
    
    
    $a = ""
    For $i = 1 To 44
        $a = $a & Chr($i + 40)           ;String erstellen )*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRST
    Next
    $a = $a & @CRLF                      ;zeilenende anhängen
    
    
    For $i = 1 To 21                     ;auf 96MB aufpumpen
        $a &= $a
    Next
    $a &= "ENDE"
    $b = StringReplace($a, @CRLF, @CRLF, 0, 1) ;crlf zählen
    $anzahl_CRLF = @extended             ;anzahl der crlf
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $anzahl_CRLF = ' & $anzahl_CRLF & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    $stringlen = StringLen($a)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $stringlen = ' & $stringlen & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    
    
    
    
    
    
    $filename = @ScriptDir & "\testdatei_96MB.txt" ;in Datei abspeichern
    FileDelete($filename)
    FileWrite($filename, $a)
    
    
    
    
    Global $filestructptr
    
    
    ;~ $asmcode = _AssembleIt2("retbinary", "_crlf") ;erstellt den asmcode
    ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $asmcode = ' & $asmcode & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    
    
    $asmcode = "0x8B7C24048B4C24088B54240C88D6C1E20888F2C1E20888F2660F6EC2660F70C0005583EC1089E3C70300010102C7430401020203C7430801020203C7430C0203030431F631ED660F6FC8660F740C37660FD7D185D2742989D083E00FD701C5C1EA0489D083E00FD701C5C1EA0489D083E00FD701C5C1EA0489D083E00FD701C583C61039CE76BF89E883C4105DC3"
    Global $codestruct = DllStructCreate("byte[" & StringLen($asmcode) / 2 - 1 & "]") ;speicher für asmcode...
    DllStructSetData($codestruct, 1, $asmcode) ;...mit code füllen
    
    
    ConsoleWrite("....bitte warten!" & @CRLF)
    
    
    ;20 blockgrößen von 4KB bis 80KB, jedes mal wird die 96MB-datei 10x gelesen
    
    
    For $r = 1 To 7
        Local $nbytes
        Local $blocksize = 1024 * $r^3
        Local $filesize = FileGetSize($filename);dateigröße
        Local $filestruct = dllstructcreate("char[" & $filesize + $blocksize + 16 & "]") ;16-byte aligned , die Funktion dazu ist in AssembleIt64() enthalten, dann hier im script löschen
        Local $filestructptr = DllStructGetPtr($filestruct);pointer auf die struct,
    
    
        Local $blocks = Ceiling($filesize / $blocksize);anzahl der zu lesenden blöcke
    
    
        $av = 0                          ;durchschnitt
    
    
        For $p = 1 To 10                 ;für jede blockgröße 10 die datei lesen
    
    
            $t = TimerInit()
    
    
    ;~ $data=fileread($filename)  ;grausam langsam....
    
    
            Local $hfile = _WinAPI_CreateFile($filename, 2, 2) ;mit der richtigen blockgröße 3-4x schneller
            For $i = 0 To $blocks - 1
                Local $blockstruct = DllStructCreate("char[" & $blocksize & "]", $filestructptr + $i * $blocksize)
                _WinAPI_ReadFileXXX($hfile, DllStructGetPtr($blockstruct), $blocksize, $nbytes) ;tick schneller durch handle statt datei
            Next
            _WinAPI_CloseHandle($hfile)
    
    
            ;falls man den string nicht braucht....
            ;*************UNBEDINGT DIE FOLGENDEN ZEILEN AUSKLAMMERN***************
    ;~         $data = DllStructGetData($filestruct, 1) ;direkt auf die struct im speicher zugreifen, DAS dauert, speicherschieben ist nicht die stärke von AutoIt
    ;~         $len=stringlen($data)
    
    
    
    
    ;~  $tt = TimerInit()
    ;~ $ret=_ASM_StringLFCharCount_Bin($data)  ;by uEZ
    ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    ;~  $mm = TimerDiff($tt)
    ;~  ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $mm = ' & $mm & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    
    
            ;Linefeeds 0x0A zählen
    ;~         $tt = TimerInit()
            Local $ret = DllCallAddress("uint:cdecl", DllStructGetPtr($codestruct), "ptr", $filestructptr, "uint", $filesize, "dword", 0x0A)
            $nr_lf = $ret[0]
    ;~         $mm = TimerDiff($tt)
    ;~         ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $mm = ' & $mm & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    
    
    
    
    ;~         $tt = TimerInit()
    ;~         $nr_lf = _AssembleIt2("uint", "_crlf", "ptr", $filestructptr, "uint", $filesize, "dword", 0x0A)
    ;~         ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $nr_lf = ' & $nr_lf & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Consol
    ;~         $mm = TimerDiff($tt)
    ;~         ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $mm = ' & $mm & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
    
    
    
    
            $m = TimerDiff($t)
            $av = $av + $m
    
    
        Next
    
    
        $av = $av / $p                   ;durchschnittliche zeit errechnen
        ConsoleWrite("WinAPI:   Read " & Int($filesize / 1e6) & "MB File    #Lines: " & $nr_lf & "   Blocksize: " & $blocksize & " bytes    time: " & Int($av) & " ms  " & @CRLF)
    
    
    Next
    
    
    ;AutoIt zum Vergleich
    $t = TimerInit()
    $data = FileRead($filename)
    $av = TimerDiff($t)
    $filesize = StringLen($data)
    ConsoleWrite(@CRLF & "Autoit:   Read " & Int($filesize / 1e6) & "MB File   time: " & Int($av) & " ms  " & @CRLF & @CRLF)
    
    
    
    
    
    
    
    
    
    
    Func _ASM_StringLFCharCount_Bin($sString) ; by UEZ
        Local $tCodeBuffer = DllStructCreate("byte ASM[27]") ;reserve memory for ASM opcode
        $tCodeBuffer.ASM = "0x8B7424048B7C240831DBAC3C0074093C0A75F783C301EBF2891FC3" ;write opcodes into memory (struct) / length: 27
        Local $tResult = DllStructCreate("dword AmountLF")
        DllCall("user32.dll", "none", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "str", $sString, "ptr", DllStructGetPtr($tResult), "int", 0, "int", 0)
        Return $tResult.AmountLF
    EndFunc                              ;==>_ASM_StringLFCharCount_Bin
    
    
    
    
    Func _TextFileRead($filename)
    
    
        Local $nbytes
        Local $blocksize = 4096 * 16
        Local $filesize = FileGetSize($filename)
        Local $filestruct = DllStructCreate("char[" & $filesize + $blocksize & "]")
        Local $filestructptr = DllStructGetPtr($filestruct)
    
    
        Local $blocks = Ceiling($filesize / $blocksize)
    
    
        Local $hfile = _WinAPI_CreateFile($filename, 2, 2)
    
    
        For $i = 0 To $blocks - 1
            Local $blockstruct = DllStructCreate("char[" & $blocksize & "]", $filestructptr + $i * $blocksize)
            _WinAPI_ReadFileXXX($hfile, DllStructGetPtr($blockstruct), $blocksize, $nbytes)
    
    
        Next
    
    
        Return DllStructGetData($filestruct, 1)
    
    
    EndFunc                              ;==>_TextFileRead
    
    
    
    
    Func _WinAPI_ReadFileXXX($hfile, $pBuffer, $iToRead, ByRef $iRead, $pOverlapped = 0)
        Local $aResult = DllCall($kerneldll, "bool", "ReadFile", "handle", $hfile, "ptr", $pBuffer, "dword", $iToRead, _
                "dword*", 0, "ptr", $pOverlapped)
        If @error Then Return SetError(@error, @extended, False)
    
    
        $iRead = $aResult[4]
        Return $aResult[0]
    EndFunc                              ;==>_WinAPI_ReadFileXXX
    Alles anzeigen
  • WLAN-Adapter wird deaktiviert

    • Andy
    • 15. März 2016 um 13:26
    Zitat von chip

    ...da es aber wie Bugfix schreibt nur bei Youtube ist und bei normalem surfen nicht, ist dieser Punkt direkt auszuschließen.

    Wieso?
    Beim " normalen Surfen" hast du permanente Eingaben, beim YT-Gucken wird idR weder Tastatur noch Maus benutzt, daher kann es durchaus sein, dass irgendein Gerät mit Stromsparmechanismen dazwischenfunkt. Bei meiner Laptop-Grafikkarte sind je nach verwendetem Programm bestimmte Beschleuniger-Funktionen aktiv, welche bspw. "Stromsparen" verhindern!
    Ich vermute daher "Energiesparen" als Grund, die Ursache findet man nur durch Ausschlußverfahren.
    Btw. gab es dieses Problem beim Tablet (Win8.1) meiner Frau vor dem Upgrade auf Win10 auch. Nach dem Aufwachen aus dem Standby war ab und zu die Netzwerkverbindung "weg" und nur durch Neustart des Geräts wiederherzustellen. Unter Win10 ist dieses Phänomen nicht mehr vorgekommen.

  • WLAN-Adapter wird deaktiviert

    • Andy
    • 14. März 2016 um 22:31

    ....das kann übrigens je nach Einstellungen auch im Netzbetrieb sein!

  • Hilfe - Barcode-Scanner

    • Andy
    • 8. März 2016 um 06:56

    Mein Script funktioniert mit diversen Scannern einwandfrei, ich bin daher hier raus...
    Eins noch, wenn man Scanneranwendungen für eine GUI schreibt, sollte man dem Fenster den TopMost-Modus gönnen, falls mobile Scanner eingesetzt und benutzt werden. Nichts ist ärgerlicher, als mit dem Scanner Barcodes einzulesen, an den Rechner zurückzukommen und dort festzustellen, dass ein freundlicher Kollege zwischenzeitlich ein anderes Programm bedient hatte...
    Ich habe u.a. daher auf Scanner mit Speicherfunktion zurückgegriffen, nach dem zurückkommen an den Rechner werden auf Knopfdruck alle Daten ausgelesen,

  • SSE Shuffle Explorer V2

    • Andy
    • 7. März 2016 um 19:56

    Jetzt weißt du endlich mal wie es mir geht, wenn ich GDI+ coden muss :P

  • Englisch im Deutschen Forum

    • Andy
    • 7. März 2016 um 13:34
    Zitat

    Kann es sein das du meinen Post falsch verstanden hast?

    Nein, kann es nicht^^
    Es kann allerdings sein, dass ich nicht in aller Deutlichkeit von mir gegeben habe, was ich von diesem Thema und der daran Beteiligten halte!
    Und dabei geht es nicht (nur) um dieses Topic...

    Niemand, aber auch wirklich NIEMAND hat sich je KONSEQUENT geäußert! Konsequent heißt, sich darüber auszulassen, dass eine (Programmier-)SPRACHE (ja Sprache, das kommt von Sprechen und ist individuell verschieden! ) sich nicht per se in eine Muttersprache "übersetzen" lässt!
    Wäre das programmiertechnische Problem von nichtfremdsprachlichen Usern kleiner oder ggf. garnicht existent, wenn die Programmiersprache mit allen ihren syntaktischen Inhalten und Eigenschaften "deutsch" wäre? Definitiv mal nicht!
    Das sieht man überaus deutlich an all den verschiedenen "Computersprachen", die ich mal in den Bereich der Esoterik schiebe. Jeder, der Lust hat, kann sich für sein individuelles Problem eine eigene Lösung zusammenbauen. Für die "Anwender" gilt, sich mit der Sprache und deren Eigenheiten abzufinden. Das gilt im Besonderen auch für die damit zusammenhängenden Foren und deren User. Grundsätzlich geht es hier um eine Computersprache die zuallererst der Computer verstehen muss, und eben NICHT der Anwender!

    Um den Zusammenhang mal deutlich zu sagen: Die Frage ist nicht, ob eine muttersprachliche "Programmiersprache" besser verstanden werden kann, sondern ob der Anwender bereit ist, diese "Sprache" anzuwenden und auch zu verstehen und sich darin einzuarbeiten!
    Wenn du in Kenia auf dem flachen Land ein Problem hast, und ein Anwohner dich in K0isuaheli anspricht, dann MUSST du dich damit auseinandersetzen! Na klar kannst du erwarten, dass dieser Anwohner Englisch oder gar Deutsch spricht, aber wenn das nicht so ist, dann musst du dir was einfallen lassen! Wenn du nun einen Dolmetscher findest, dann wird dein "Problem" kurzfristig gelöst, aber was nützt dir das, wenn du am nächsten Tag wieder ein Problem hast, und es ist eben KEIN Dolmetscher greifbar?!
    Interessant in diesem Zusammenhang wäre die Antwort des Dolmetschers, wenn du ihn fragen (verlangen) würdest, dich in den nächsten Wochen (kostenlos) durch Kenia zu begleiten und permanent alles zu übersetzen, was es kommunikativ abzuwickeln gibt....

    ich bin ziemlich sicher, dass es bei all diesen Diskussionen garnicht darum geht, "unverständlich in einer Fremdsprache" einen Hinweis zur Lösungsmöglichkeit zu bekommen und damit nicht weiterzukommen, sondern eben " schön in der Muttersprache erklärt", ein Copy&Paste-Beispiel, einzufügen ins eigene Script!

  • Englisch im Deutschen Forum

    • Andy
    • 6. März 2016 um 19:07

    Hi,
    ich verstehe ehrlich gesagt das Problem nicht!
    Es quieken einige darüber, dass zu Fragen hier im Forum in anderssprachige Foren verwiesen/verlinkt (direkt in den Thread/Post!!! ) wird.
    Vielleicht hat es sich noch nicht herumgesprochen, aber NIEMAND hier hat je eine höflich gestellte Frage mit Hinweis auf ein unverständliches, weil fremdsprachliches, Forum "abgewatscht"!
    Wenn jemand keine oder nicht genügend Fremdsprachenkenntnisse hat, dann ist das die eine Sache, sich aber hinzustellen und quiekenderweise sich darüber zu beschweren, daß in ein fremdsprachliches Forum verlinkt wird, eine andere.
    Wo ist der Thread, in dem bei der Nachfrage "...Danke für den Link, aber ich verstehe trotz Google translate absolut nicht, um was es dort geht und auch anhand des dort geposteten Scripts kann ich mir auch keinen Reim drauf machen, bitte um Erklärung! " in unserem Forum jemand schreibt: " Pech gehabt, dann lerne halt die Fremdsprache!"?

    Wenn allerdings jemand aus der Kandidatenszene "leg mir mal einer den Arm aus der Sonne" den üblichen 2-zeiligen Thread "...und ich brauche dringend..." postet und als Antwort auch noch einen Link in ein anderssprachiges Forum erhält weil er selbst im deutschen Forum nichts gefunden hat, und sich DANN über die erbrachte Such-Leistung eines unserer Forianers AUCH NOCH BESCHWERT, dann habe ich dafür absolut kein Verständnis!

    Wer mit den gebotenen Leistungen hier im Forum nicht zufrieden ist, dem steht jederzeit offen, eines der vielen weiteren deutschsprachigen Foren zu besuchen und dort kompetente Antworten in unserer Landessprache zu bekommen!

  • Hilfe - Barcode-Scanner

    • Andy
    • 6. März 2016 um 00:56

    @Alina, das war das Script des TE, ich habe nur einige Zeilen geändert so dass es funktioniert.

  • Hilfe - Barcode-Scanner

    • Andy
    • 4. März 2016 um 19:03

    Hi,
    generell ist es völlig egal, an welches Control du den String vom Scanner sendest.
    Wie von dir vermutet, ist das _ispressed() das Problem. Das brauchst du aber auch garnicht, da das @CRLF ja sowieso im String ist und dementsprechend abgefragt/verarbeitet werden kann.
    Du brauchst auch keinen extra Button und auch kein extra Event (obwohl es sicherlich ein ENTER-Event in der InputBox gibt)

    AutoIt
    #include <array.au3>
    #include <file.au3>
    #include <MsgBoxConstants.au3>
    #include <date.au3>
    #include <GuiButton.au3>
    #include <GuiEdit.au3>
    #include <GuiStatusBar.au3>
    #include <GUIConstantsEx.au3>
    #include <FontConstants.au3>
    #include <Misc.au3>
    
    
    HotKeySet("{ESC}", "Terminate")
    
    
    Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc")
    Global $zeitstempel
    Global $value[7]
    Global $inhalt[7]
    Global $hDLL = DllOpen("user32.dll")
    
    
    Main()
    Func Main()
    Global $key
        GUICreate("")
    	  Local Const $sFont = "Comic Sans Ms"
    		 Global $label_1 = GUICtrlCreateLabel("Ich brauche Nachschub", 10, 10, 300, 35)
    		 GUICtrlSetFont($label_1, 15, $FW_NORMAL, $GUI_FONTUNDER, $sFont)
    		 Global $auftrags_nr = GUICtrlCreateInput("", 10, 70, 300, 35)
    		 GUICtrlSetFont($auftrags_nr, 15, $FW_NORMAL, $sFont)
    		 GUISetState(@SW_SHOW)
    Local $idMsg
    	$trigger = 0
    While $trigger = 0
    
    
    	  $idMsg = GuiGetMsg()
    	  switch $idMsg
    		 Case $GUI_EVENT_CLOSE
                    ExitLoop
    		  case $auftrags_nr
    				consolewrite(guictrlread($auftrags_nr)&@crlf)
    				GUICtrlSetData($auftrags_nr,"")
    	 EndSwitch
    
    
    WEnd
    EndFunc
    
    
    
    
    
    
     Func Terminate()
    	Exit
    EndFunc
    Alles anzeigen
  • String in Array übergeben jeden Buchstaben einzeln

    • Andy
    • 4. März 2016 um 07:39

    Hi,
    meine Frage ist, wieso jemand ein Array von einzelnen Buchstaben benötigt, wenn doch schon ein String ein Array IST!
    Jedes Item im String kann man einfachst über seinen Index ansprechen...StringMid().
    Strings bearbeitet man idR. mit Stringfunktionen, denn dafür sind die gemacht.
    Es handelt sich imho also um das klassische X-Y-Problem (Link dazu in meiner Signatur)

    Zitat von autoBert

    denn wer sein Werkzeug nicht kennt kann es nicht einsetzen

    FullAck!!! Besser kann man es nicht beschreiben...
    Es ist auch nicht problematisch, ein Werkzeug nicht zu kennen, problematisch ist, ein Problem nicht beschreiben zu können!


    Zitat von Blaxxun

    Ich komme aus dem Bereich 3D Modeling und VFX und ich habe ganze Bücher an Text geschrieben um Neulingen zu helfen.

    Wenn das so wäre, dann hättest du zumindest Grundlagen im Verwenden von Nachschlagewerken. Du beherrscht aber nicht einmal die Grundlage des einfachen Verstehens von Hilfstexten, siehe:

    Zitat von Blaxxun

    Mit String split habe ich es auch schon probiert, aber das braucht wieder einen "delimiter" welchen ich ja gar nicht habe in meiner String Variable.

    In der Hilfe ist die Verwendung von Leerstrings als Delimiter beschrieben...


    Ich vermute einen Zweit/Mehrfachaccount, das ist in letzter Zeit (nicht nur hier im Forum) sehr im Mode gekommen. Wenn man mit bestimmten (An-) Forderungen bei den "Profis" nicht weiterkommt (du hast dich mit den Aussagen in diesem Thread von sämtlichen "Profis" distanziert) , dann versucht man den "zweiten Bildungsweg". Irgendwer wird sich immer erbarmen, einem den "Arm aus der Sonne zu legen"...

  • CPU effektiver bei Script Ausführung einsetzten

    • Andy
    • 2. März 2016 um 07:27
    Zitat von AspirinJunkie

    Ich weiß nur halt nicht wie du das hinbekommst den Wertebereich jedes Bytes auf 33-127 einzudampfen.
    Alle 4 durch Verschieben und Einzelbehandlung anpassen?

    Etwas anderes wird nicht funktionieren... :(

    Hier der Assemblercode, ca. doppelt so schnell wie _Crypt_GenRandom(). Mal schauen, was deine Idee mit dem MOD (DIV) bringt, das muss aber für jedes Byte gemacht werden!

    Code
    #cs _RtlRandomEx
        Use32                                ;32Bit!
    
    
        mov edi,dword[esp+4]                 ;pointer struct
        mov ecx,dword[esp+8]                 ;anzahl
        mov ebx,dword[esp+12]                ;pointer auf RtlRandomEx
        mov esi,dword[esp+16]                ;pointer seed
    
    
        shr ecx,2                            ;anzahl/4 => 4 bytes = 1 dword
        sub ecx,1                            ;0 bis anzahl-1
    
    
        push ebp                             ;registerinhalt retten, dieses register wird von RtlRandomEx nicht zerstört
        mov ebp,ecx                          ;mit anzahl füllen
    
    
        _loop:                               ;for i=anzahl-1 to 0
    
    
        push esi                             ;seedadresse vorbereiten
        call ebx                             ;call RtlRandomEx , zerstört ecx,edx, Zufallswert in eax
    
    
        mov [edi+ebp*4],eax                  ;zufallswert dword in struct speichern...
    
    
        sub ebp,1                            ;...so lange...
        jns _loop                            ;...bis kleiner als null
    
    
        pop ebp                              ;ebp wieder herstellen
        ret
    
    
    #ce
    Alles anzeigen
  • CPU effektiver bei Script Ausführung einsetzten

    • Andy
    • 1. März 2016 um 23:53
    Zitat von AspirinJunkie

    Gibt es in Assembler einen Integer-Modulo?

    Ja, als "Abfall" der Division erhält man den "Rest" . Allerdings ist DIV schon sehr "teuer" (jaja, bissl bekloppt darf man sein ^^ ). Weiterhin gehe ich einfach mal davon aus (korrigiere mich bitte wenn nötig! ), daß bei gleichverteilten RtlRandomEx-32-Bit-Ergebnissen, auch die darin enthaltenen einzelnen Bytes gleichverteilt sind.
    Somit bekomme ich 4 zufällige Bytes! Und brauche also auch nur 1/4 der Berechnungen!
    Über den dicken Daumen bin ich mit dem Assemblerscript bissl schneller als _Crypt_GenRandom(). Jedenfalls bei durch 4 teilbaren Byte/Char-Mengen :D

    Noch schön verpacken....

  • CPU effektiver bei Script Ausführung einsetzten

    • Andy
    • 1. März 2016 um 13:27
    Zitat von MadCatz

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

    ggf. solltest du dir das Thread/Task-Management von Windows anschauen.

    Zitat von MadCatz

    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.

    Du hast eine Quadcore, daher die 25%. Windows verteilt die 100% Last EINES Threads/Tasks auf 4 Kerne, daher 25%. Du kannst das einfach im Taskmanager beeinflussen, wenn du den Task/Thread EINEM Core zuordnest (Rechtsklick auf den Prozess).


    Ich werde mal was basteln, die 15 Sekunden sollten doch zu schlagen sein^^

  • CPU effektiver bei Script Ausführung einsetzten

    • Andy
    • 1. März 2016 um 07:40

    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.

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™