Funktion Assign

  • Da du globale Variablen ansprachst:

    Was bei einem Dictionary auch viele nicht wissen:
    Die AutoIt-Variable enthält lediglich eine Referenz (Pointer/Verweis) auf das Dictionary-Objekt und nicht das Objekt selbst.

    Daher kann man das gleiche Dictionary in verschiedenen Funktionen verwenden, ohne eine globale Variable zu verwenden:

    Umgekehrt muss man dies natürlich auch beachten, wenn man mal tatsächlich eine Kopie und keinen Verweis eines bestehenden Dictionaries benötigt. In dem Fall muss man Helferlein wie diese Funktion bemühen:

    Code
    Func _cloneDictionary($oDic)
        Local $oRet = ObjCreate("Scripting.Dictionary")
    
        $oRet.CompareMode = $oDic.CompareMode
        For $sKey in $oDic.Keys
            $oRet($sKey) = $oDic($sKey)
        Next
    
        Return $oRet
    EndFunc
  • Das es sich um einen Pointer handelt finde ich gut, ich habe mich schon gefragt wie ich die UDF wohl umbasteln müsste wenn immer das ganze objekt mit gegeben werden muss. Ähnlich tue ich das in der UDF, nur das dort der Socket der Pointer ist. Ich werde ausführlich testen müssen ob sich aus entweder dem dictobj oder den assosiativen arrays tatsächlich ein performance gewinn ergibt. Denn wenn ja dann lohnt sie die nutzung bestimmt.

  • Ich werde ausführlich testen müssen ob sich aus entweder dem dictobj oder den assosiativen arrays tatsächlich ein performance gewinn ergibt. Denn wenn ja dann lohnt sie die nutzung bestimmt.

    Performance ist hier gar nicht die Frage.
    Wenn ich dich richtig verstehe kreierst du zig globale Variablen dynamisch mit Assign?
    Über diese kannst du jedoch nicht iterieren. Sprich: Du weißt im Grunde nie genau, welche Variablen nun tatsächlich alle definiert sind.
    Das führt sicher irgendwann dazu, dass diese im Speicher verbleiben auch wenn sie nicht mehr gebraucht werden oder mal von einer anderen Funktion überschrieben werden die zufällig den selben Variablennamen verwendet usw.

    Bei kleinen Projekten vielleicht noch überschaubar - bei größeren Sachen auf jeden Fall Finger weg.

  • Über diese kannst du jedoch nicht iterieren. Sprich: Du weißt im Grunde nie genau, welche Variablen nun tatsächlich alle definiert sind.
    Das führt sicher irgendwann dazu, dass diese im Speicher verbleiben auch wenn sie nicht mehr gebraucht werden oder mal von einer anderen Funktion überschrieben werden die zufällig den selben Variablennamen verwendet usw.

    Doch ich kann itterieren, ich weiß genau wo und wann welcher Socket welche variablen trägt und in welch einem Zustand diese sich befinden. Und zufällig wird der gleiche variablen name auch nicht verwendet, deshalb nicht weil die socket nummer teil der variable ist und diese nicht zur gleichen zeit zweimal existiert.

    Ich zeige dir mal wie ich das mache

    Wenn du dir die funktionen angesehen hast, wirst du bemerkt haben das jede neu erstellte variable gespeichert wird und das diese mit einem funktionsaufruf einfach mit Null überschrieben werden können. Und es ist auch möglich sich die variablen jederzeit anzusehen.

    Man könnte jetzt noch weitergehen und eine erstellung von variablen sogar verneinen wenn nicht vorher die gruppe schon erstellt wurde. Würde man dann, sobald der socket entfernt wird, auch die gruppe entfernen, dadurch also verhindern dass weitere variablen (versehentlich) erstellt oder neu beschrieben werden, dann wäre man auch geschützter gegen memory leaks.

    Ich habe zig tests gemacht mit Assign und Eval, man muss eben sorgfältig mit ihnen umgehen, aber im gegenzug bekommt man dafür sehr kurze schreib und zugriffszeiten.

  • Ich habe zig tests gemacht mit Assign und Eval, man muss eben sorgfältig mit ihnen umgehen, aber im gegenzug bekommt man dafür sehr kurze schreib und zugriffszeiten.

    Assign/Eval wären tatsächlich bei der Zuweisung als auch dem Zugriff etwas schneller als das Scripting.Dictionary.
    Dies aber nur beim reinen Assign/Eval.
    Durch deine Verwaltungsfunktionen drumherum kehrt sich dies massiv um.

    Folgendes Testskript hierzu:

    erbrachte bei mir folgende Ergebnisse:

    Code
                  Assign: 0.00415 ms
          Dictionary Add: 0.00902 ms
     _storageS_Overwrite: 2.96033 ms
    
                    Eval: 0.00193 ms
          Dictionary Get: 0.00443 ms
          _storageS_Read: 0.00971 ms

    Hauptgrund bei _storageS_Overwrite hierfür ist, dass die Elemente einzeln per ReDim hinzugefügt wird.
    Der Effekt steigt dort also exponentiell (oder quadratisch? - bin gerade nicht sicher) mit der Anzahl der Variablen.

    Man könnte zwar noch einiges rausholen, wenn man ein dynamisches Array verwendet aber ans Dictionary wird es auch dann nicht rankommen.

    ; sind sie jetzt wirklich gelöscht?

    ; nö, mir ist kein weg bekannt globale variablen zu löschen, aber mann kann sie mit Null überschreiben

    Exakt so wie du vermutest. Ein Überschreiben mit NULL löscht die Variable nicht.
    Das würde man nur erreichen, wenn es eine lokale Variable ist und der Scope (also die Funktion) beendet wird.
    Sprich: Mit jeder weiteren Variable steigt der Speicherverbrauch weiter bei dir, ohne dass du viel dagegen tun kannst, da die Variablen bei dir ja implizit global sind.

    Beispiel zur Verdeutlichung, dass NULL bei Assign den Speicherbereich nicht freiräumt:

    Anders sieht es auch hier beim Dictionary-Objekt aus.
    Dort kann man tatsächlich die Speicherbereiche der Elemente freigeben:

    Einmal editiert, zuletzt von AspirinJunkie (1. Februar 2022 um 18:51)

  • Massiv klingt fast untertrieben, das ist ein unterschied wie tag und nacht :huh: . Ich hab zum testen jetzt mal eine kombination aus Assign/Eval und dem DictObj in _storageS gebaut.

    Code
                  Assign: 0.00204 ms
          Dictionary Add: 0.00396 ms
     _storageS_Overwrite: 0.00734 ms
    
                    Eval: 0.00111 ms
          Dictionary Get: 0.00290 ms
          _storageS_Read: 0.00646 ms

    Und das es möglich ist das Dict auch zu löschen ist ebenfalls ein massiver vorteil gegenüber den Globalen Variablen


    EDIT

    Und jetzt nochmal das ganze, aber ohne Assign und Eval

    Von der Geschwindigkeit her änderte sich nichts, aber es funktioniert jetzt gänzlich ohne Assign/Eval

    Einmal editiert, zuletzt von Lambdax (1. Februar 2022 um 20:08)

  • Oke ich hab was interessantes herausgefunden. Ich hab die neue dictobj method in die UDF eingebaut und mich dann doch gewundert warum die UDF plötzlich viel langsamer war als zuvor. Erst dachte ich an ein problem mit der integration aber dem war nicht der fall.

    Ich hatte so eine idee, deshalb hab ich deinen test von oben erneuert und die zu schreibenden daten vergrößert. Dabei ist mir aufgefallen das das dictobj viel schneller bei kleinen daten ist aber langsamer bei großen.

    Hier wird jetzt ein datenset von 1 MB erstellt und in das obj als auch in die globalen gegeben. Und die anzahl an durchläufen sind verringert, der RAM soll ja nicht volllaufen.

    Code
                  Assign: 0.00147 ms
          Dictionary Add: 2.90448 ms
     _storageS_Overwrite: 0.15680 ms
    
                    Eval: 0.00113 ms
          Dictionary Get: 1.91853 ms
          _storageS_Read: 0.00772 ms