Beiträge von AspirinJunkie

    Ohne konkrete Anwendungsfall kann man eigentlich gar nicht Aussagen dazu treffen welche Methode, welche andere schlägt oder nicht. Die benötigten Kriterien sind schlicht noch nicht klar.


    Zur besseren Einordnung was der eigentliche Vorteil von FileReadLine ist, zitiere mich mal von oben selbst:

    Unabhängig davon ob du alle Zeilen in einem Array benötigst oder die Zeilen gleich in der Schleife behandeln kannst


    Die im 2. Post vorgeschlagene Methode per Stringsplit (oder auch ggf. noch schneller Regex) schlägt die FileReadLine()-Funktion trotzdem noch um Längen. :rtfm:

    Erstens hinkt der Speedvergleich etwas - denn StringSplit haut die Zeilen nur in ein Array - die einzelnen Elemente werden jedoch kein einziges mal angefasst.
    Ein jedoch unwahrscheinliches Szenario ist es hierbei aber dass die Werte nur in ein Array landen sollen ohne jemals weiterverarbeitet zu werden.

    Die wirklich wichtige - jedoch fehlende - Information ist aber: Müssen die einzelnen Zeilen unbedingt in ein Array oder würde es nicht eventuell auch reichen sie einmal durchzuiterieren und einzeln zu behandeln?

    Wissen wir jedoch nicht.

    Wäre dies aber hypothetisch der Fall, dann ist die Array-Variante bei mir ca. 17s (wenn man die Einzelelementbehandlung fairerweise auch mit in die Messung einbezieht) gegen 26s klar schneller. Also ca. ein Faktor von 1:1,5. Aber dies ist ja nur ein Kriterium von vielen möglichen.

    Ein anderes wäre z.B. der RAM-Verbrauch. Da ergibt die FileReadLine-Loop bei mir 6,2mb. Die StringSplit-Variante dagegen stolze 2,3GB. Das wäre dann ein Faktor von 380:1...


    Das Grundproblem ist weiterhin das folgende und vorher macht eine Diskussion über die "bessere" Methode nur bedingt Sinn:

    Zeig mal die Anwendung, für die man diese Konstruktion überhaupt benötigt.


    Btw: Warum eigentlich Fileread + StringSplit? Was spricht denn gegen ein simples FileReadToArray? (Edit: das ist ja noch langsamer - da läuft doch irgendwas schief :/)

    Unabhängig davon ob du alle Zeilen in einem Array benötigst oder die Zeilen gleich in der Schleife behandeln kannst ist der Grund für das langsame Skript dass du bei filereadline den Zeilenparameter verwendest. Dabei wird bei jedem einzelnen Aufruf die Datei von Anfang an durchlaufen und die Anzahl der Zeilen gezählt bis die gewünschte Zeile erreicht ist. Jedes Mal...


    Daher Hilfe zu filereadline lesen. Dort steht wie man es richtig macht: Datei mit fileopen öffnen und dann filereadline OHNE Zeilenparameter aufrufen. Dann wird nämlich immer die jeweils nächste Zeile ausgelesen anstatt von Anfang an durchlaufen.

    Eine Datenstruktur, welche ich nahezu täglich verwende (z.B. über das Scripting.Dictionary-Objekt) ist die Hash-Tabelle.

    Wie diese funktioniert war mir zwar in den absoluten Grundzügen klar, aber im Grunde war es dann eben doch eher eine Art Blackbox für mich.


    Das wollte ich nun ändern und ein tieferes Verständnis für die Funktionsweise einer Hash-Tabelle erlangen.
    Was gibt es da für einen besseren Ansatz als einfach mal selbst eine komplette Hash-Tabelle in AutoIt zu implementieren?

    Herausgekommen ist dabei folgende UDF.
    Diese ist ausdrücklich lediglich als Übungsprojekt zum Verständnis gedacht und kann nicht mit z.B. Scripting.Dictionary mithalten (habe ich auch gar nicht erst getestet). (wie sich herausgestellt hat, kann diese bei einer großen Elementanzahl eben DOCH mithalten).

    Einige Dinge bergen auch noch deutliches Optimierungspotential (z.B. eine vernünftige Hash-Funktion) und sind erst einmal nur für das grundsätzliche Funktionieren implementiert.

    Wer sich jedoch wie ich ein bisschen mehr mit Hash-Tabellen auseinander setzen möchte, dem kann eventuell diese UDF beim Verständnis ein wenig weiterhelfen.


    Kurzes Beispiel damit jeder sieht, dass sie tatsächlich funktioniert:

    Dateien

    • hashtable.au3

      (6,99 kB, 14 Mal heruntergeladen, zuletzt: )

    Ich habe mir das ganze nochmal mit der aktuellen Beta angesehen (3.3.15.3).

    Dieses mal getrennt im Hinblick auf assoziative Arrays und sequentielle Arrays.


    Kurz zusammengefasst: Es gibt nicht DIE Datenstruktur die alle anderen outperformed, sondern es hängt viel mehr davon ab wieviele Elemente die Datenstruktur schlussendlich enthält.


    Zeitaufwand für das (einzelne hinzufügen) Erstellen eines assoziativen Arrays mit N Elementen:

    Zeitaufwand für das (einzelne hinzufügen) Erstellen eines sequentiellen Arrays mit N Elementen:

    Zeitaufwand für das (jedes einzeln) Auslesen aller Elemente eines assoziativen Arrays mit N Elementen:

    Zeitaufwand für das (jedes einzeln) Auslesen aller Elemente eines sequentiellen Arrays mit N Elementen:


    Testskripte und Diagramme als PDF liegen im Anhang.


    Edit: Assoziatives Array als 2D-Array mit binärer Suche hinzugefügt - interessantes Ergebnis da dies bei großen Datenmengen auch Map und Dictionary überholt.

    Ähm Leute schaut euch mal seinen ersten Beitrag hier im Forum (widerspricht sich schonmal mit seiner Aussage, dass er sich extra wegen dem Auto-Thema angemeldet hat) an und nach dem Text hier kann man ziemlich sicher von ausgehen, dass es sich hier um einen Bot handelt.

    Das Skript hängt tatsächlich nicht sondern ist wirklich so langsam.


    Der Grund ist folgender: In der UDF wird der String schrittweise mit StringRegEx auseinander genommen.

    Das heißt also zig einzelne Aufrufe an StringRegExp() wo jedesmal der riesen String an die Funktion übergeben wird.

    Hierbei wird jedoch nicht einfach nur der Pointer auf den String übergeben sondern anscheinend(!) eine lokale Kopie des Strings erzeugt und übergeben.

    Mal ein einfaches Skript zur Demonstration:

    Hier sieht man, dass die Ausführungsgeschwindigkeit direkt von der Größe des Strings abhängt obwohl das Pattern selbst nur das erste Zeichen auswertet.

    Wenn nun also jedes RegEx - egal wie simpel es ist - eine halbe Sekunde braucht, dann ist klar dass dies bei 100.000en Aufrufen die für eine solche Datei nötig wären, unheimlich hohe Bearbeitungszeiten herauskommen.


    So - wie nun also damit umgehen? Das Grundproblem liegt außerhalb meines Einflussbereiches.

    Ich werde das eventuell mal aufbereiten und im englischen Forum vortragen - in der Hoffnung, dass intern auf by Reference umgestellt wird.

    Bei StringLeft() oder StringMid() hat man dieses Phänomen übrigens nicht.

    Oder eine ganz andere Lösung die ich noch nicht sehe.


    Für so große JSON-Strings sollte man daher auf AutoIt-externe Lösungen zurückgreifen.

    Für diesen Fall gibt es z.B. die >>JSMN-basiert UDF<<. Diese verwendet JSMN als Parser. Das Parsing wird also nicht von AutoIt erledigt.

    Des Weiteren wird auch nicht der ganze String in native Datentypen gecastet sondern es wird lediglich eine Liste erzeugt wo an welcher Stelle welche Datentypen stehen.

    So ist die Struktur erstmal ganz fix geparsed und die Objekte selbst werden erst gecasted wenn wirklich auf sie zugegriffen wird.

    Kurz und knapp: Das ist deutlich fixer als eine AutoIt-basierte Lösung wie bei mir und sollte insbesondere bei derart großen Files die passende Alternative darstellen.


    Außer natürlich es findet sich noch ne Lösung für die Übergabe der großen Strings an StringRegExp() ;-)

    Da es sich um eine json-Datei handelt ist es naheliegend wenn man einen entsprechenden JSON-Parser verwendet.

    Dann ist die Abfrage simpel und vor allem stabil denn die Definition "zwischen 3. und 4. Anführungszeichen" passt vielleicht auf den aktuellen Zustand aber wenn zusätzliche Infos mal reinkommen oder die Reihenfolge der Values wechselt dann crasht das ganze.


    Mit der UDF von hier siehts so aus:


    Edit:

    Ich habe eine Funktion geschrieben welche mittels FileRead eine Variable mit Text abgefüllt

    Wenn damit gemeint ist, dass der genannte Abschnitt vorher aus einer größeren JSON-Datei rausgeholt wird, dann kannst du dir den Schritt bei Verwendung eines JSON-Parsers direkt sparen, da du direkt den gewünschten Wert aus dem Gesamtkonstrukt holen kannst ohne erst vorher einen bestimmten Teilbereich herauszuschälen. Bei Bedarf poste einfach mal die ganze Datei.

    Solange ich nicht in den Quellcode von Run sehen kann, ist das Thema somit "gelöst".

    ShellExecute ruft die Windows-API-Funktion >>ShellExecute<< (oder auch ShellExecuteEx) auf.

    Run() ruft die Windows-API-Funktion >>CreateProcess<< auf.

    Dort findet sich folgender wichtiger Hinweis:

    The new process runs in the security context of the calling process.

    Heißt: Es ist schlicht gar nicht vorgesehen, dass das aufrufende Programm in einem anderen Security-Kontext laufen kann. Daher schlägt der Aufruf auch fehl da im derzeitigen Kontext nicht genügend Rechte für die Anforderung bereit stehen.


    Edit: Achso - du wolltest ja den Quellcode zur Run()-Funktion:

    Die anderen Lösungen haben bisweilen den Vorteil, daß ich nur eine Klammer entfernen kann, da es doch evtl. vorkommt, daß noch eine weitere Klammer im String steht.

    Was wie in welcher Form alles auftauchen kann, lässt sich am besten anhand von ein paar Beispielen beschreiben.

    Dann kann man entsprechende Regeln in Form von regulären Ausdrücken daraufhin definieren (die StringRegEx-Funktionen).

    Das Problem hieran ist, dass man sich erstmal in diese einarbeiten muss, da deren Syntax alles andere als autoplausibel ist.

    Es lohnt sich aber definitiv - eben weil es nicht AutoIt-spezifisch ist sondern überall auftaucht.

    Auch hier bei uns gibt es ein >>entsprechendes Tutorial<<.


    Zum Nachvollziehen ist daher alpines Variante erst einmal die bessere Variante, da man sich diese ohne groß einlesen selbst erschließen kann.


    Gib also mal ein paar Beispiele was wie auftauchen kann und entfernt werden soll.

    Hallo "Gürteltier",

    Nene - das ist ein Erdferkel...


    Ich hoffe mal, daß Du nicht wie ich auf Aspirin angewiesen bist.

    Meine letzte Aspirin habe ich wohl vor ca. 2 Jahren mal genommen.

    Der Name kommt aus meiner präpubertären Phase (war ca. 12 Jahre) im Jahre 1999 - der Hochzeit von AOL - als auch Normalsterbliche das Internet für sich entdeckten und es unglaublich witzig fanden ganz "verrückte" Nicknames in diesem neuen Ding namens "Chat" zu verwenden.

    Über die Zeit kam dann immer mehr Bartwuchs dazu - der Nick blieb jedoch.


    Im Grunde mag ich ihn also selbst nicht - kann und will ihn jedoch nicht mehr ändern, da eine gewisse Identität hieran geknüpft ist.

    Eventuell wäre ein Ordnerauswahldialog auch eine komfortable Lösung?:


    Na das war ja mal ekelhaft zu debuggen...

    Problem war den Fehler überhaupt erst einmal zu detektieren.

    Ursache war ein Stack-Overflow bei der PCRE-Engine aufgrund einem zu exzessiven Backtracking bei langen Strings.

    Die Behebung war dann ein Klacks: Einfach ein + hinzufügen (um einen Quantifier possesiv zu machen).


    Jetzt sollte es aber auch mit deiner Aerosmith_Lesbar.json klappen.

    Selbst die Aerosmith.json parst er nun, obwohl die mir jeder JSON-Validator mir die um die Ohren haut.


    Als Nebeneffekt sollte auch die Performance wieder ein Stück gestiegen sein.

    Ich bin dran wird aber wohl noch ne Weile dauern, da das Debugging in dem Fall echt eklig ist.

    Hab ein paar Vermutungen und auch schon einen ersten Bug gefunden.
    Dürfte die nächsten Tage aber hinreichend Zeit dafür fnden (Quarantäne - Yeah!).

    Mach mal ein Sleep(3000) hinter das_IECreate. Dann sollte es funktionieren (noch abhängig von deiner Verbindungsgeschwindigkeit).

    Ein _IELoadWait bringt in dem Fall nichts, da die Seite ja m Grunde vollständig geladen wurde. Die anderen Inhalte werden ja dynamisch per Ajax nachgeladen.


    Ganz ehrlch: Such dir ne andere Quelle für die Ermittlung der aktuellen JAVA-Version - mit der Seite wirst du nicht viel Freude haben.


    Edit:Hier in bisschen anderer Form formatiert findest du die jeweils aktuellen Versionen hier:

    http://javadl-esd-secure.oracle.com/update/baseline.version

    Die Info steht dort nicht im Quelltext sondern wird erst durch das eingebettete Javascript per Ajax nachgeladen.

    Da InetRead (und damit _InetGetSource) kein Javascript ausführt kommst du also nicht an die Info.


    Du brauchst also eine andere Quelle für deine Info oder du lässt den Code von einem Browser ausführen und liest dann die Infos aus.

    Mit _IEBodyReadHTML glaube ich könntest du weiter kommen.

    Für sowas sind reguläre Ausdrücke ideal.

    Ein Tutorial hierzu findest du >>hier<<.


    Dann sollte dich folgendes ein Stück weiter bringen:

    AutoIt
    #include <Array.au3>
    Global $sFile = FileRead("Test.log")
    For $aMatch In StringRegExp($sFile, "addCoin: (-?\d+) von (\d+)", 4)
    _ArrayDisplay($aMatch)
    Next