Intelligentes Array

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Intelligentes Array

Beitrag von cxAlex »

Hier mal ein Code für ein Intelligentes Array. Ich hab es mir für ein Management System ausgedacht, speziell für sehr hohe Indexes, wie Bsp. hWnds, ClientIDs, ....

Der Witz daran ist das z.B. wenn ich den Index 1205381 habe nicht 1 Mio. Einträge füllen muss sondern nur der Eintrag 1205381 erstellt wird. Hat natürlich zur Folge das jeder Eintrag mehr Platz im Speicher braucht als bei einem klassischem, ist also eher nicht dazu geeignet wenn man ein Array von 0 - ... füllen will. Das ganze basiert auf Ebenen. Jede Ebene umfast die Zahlen 0 - 9. Ist die Zahl größer wird eine Eben tiefer gegangen. 1205381 währe auf Ebene 1-8-3-5-0-2-1 (Tiefe 7).

Das Array ist trotzdem sehr schnell, wobei es die Möglichkeit gibt die Zahl vor dem Indexen zu drehen, was sich wie folgt auswirkt:
Bereich: 0 - 10 Mio, ohne drehen hat geschrieben:Schreiben & Erstellen: Zugriffe: 6958942.00/Sek
Lesen: Zugriffe: 8097166.00/Sek
Aufräumen: 0.44 sek
Bereich: 0 - 10 Mio, mit drehen hat geschrieben:Schreiben & Erstellen: Zugriffe: 4849660.50/Sek
Lesen: Zugriffe: 5333333.50/Sek
Aufräumen: 0.19 sek
Bereich: 10 Mio - 20 Mio, ohne drehen hat geschrieben:Schreiben & Erstellen: Zugriffe: 2006420.50/Sek
Lesen: Zugriffe: 3315649.75/Sek
Aufräumen: 12.77 sek
Bereich: 10 Mio - 20 Mio, mit drehen hat geschrieben:Schreiben & Erstellen: Zugriffe: 4050222.75/Sek
Lesen: Zugriffe: 4384042.00/Sek
Aufräumen: 0.17 sek
Man sieht, bei kleineren Zahlen drückt das drehen auf die Performance, bei höheren verbessert es sie.Auf jedem Fall bringt das drehen eine bessere Speichernutzung und eine schneller Aufräumzeit (im 2. Test 75x fach schneller!)

Viel Spaß damit, Gruß cxAlex:

PS: Währe froh wenn jemand testen könnte ob der x64 - DrehCode funktioniert, hab hier leider keine Möglichkeit das zu testen.

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Intelligentes Array
; Author: Alexander Aigner
; PB 4.3+ x86/x64
; ------------------------------------------------------------------------------------

Structure IArray_Data ; Daten Element
  *Next.IArray ; Tiefere Ebene
  Value.i ; Eintrag
EndStructure

Structure IArray_Holder ; Array Holder
  Entry.IArray_Data[10]
EndStructure

Structure IArray ; Array Main - Struktur
  IArray.IArray_Holder
EndStructure

Procedure New_IArray() ; Neues Array anlegen
  Protected *IArray = AllocateMemory(SizeOf(IArray))
  ProcedureReturn *IArray
EndProcedure

Procedure TurnVal(Val) ; (x86, x64)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    !MOV EAX, dword[p.v_Val]
    !MOV EBX, 10
    !MOV ECX, 0
    !@@:
    !OR EAX, EAX
    !JZ @f
    !IMUL ECX, EBX
    !CDQ
    !IDIV EBX
    !ADD ECX, EDX
    !JMP @b
    !@@:
    !MOV EAX, ECX
    ProcedureReturn
  CompilerElse
    !MOV RAX, qword[p.v_Val]
    !MOV RBX, 10
    !MOV RCX, 0
    !@@:
    !OR RAX, RAX
    !JZ @f
    !IMUL RCX, RBX
    !CDQ
    !IDIV RBX
    !ADD RCX, RDX
    !JMP @b
    !@@:
    !MOV RAX, RCX
    ProcedureReturn
  CompilerEndIf
EndProcedure

Procedure IArray_Set(*IArray.IArray, Index.i, Value.i) ; Eintrag setzen
  Protected *IArrayEntry.IArray_Data, *cur.IArray_Holder
  *cur = @*IArray\IArray
  
  ; Probeweise auskommntieren:
  Index = TurnVal(Index)
  
  ; Element finden
  Repeat
    ; Aktuelles Element
    *IArrayEntry = @*cur\Entry[Index%10]
    Index/10
    If Index ; Weiter in die Tiefe
      If Not *IArrayEntry\Next ; Noch nicht angelegt?
        *IArrayEntry\Next = AllocateMemory(SizeOf(IArray))
      EndIf
      ; eine Ebene tiefer gehen
      *cur = *IArrayEntry\Next\IArray
    EndIf
  Until Not Index
  
  ; Eintrag schreiben
  *IArrayEntry\Value = Value
EndProcedure

Procedure IArray_Get(*IArray.IArray, Index.i)
  Protected *IArrayEntry.IArray_Data, *cur.IArray_Holder
  
  ; Probeweise auskommntieren:
  Index = TurnVal(Index)
  
  ; Element finden ( Siehe oben)
  *cur = @*IArray\IArray
  Repeat
    *IArrayEntry = @*cur\Entry[Index%10]
    Index/10
    If Index
      If Not *IArrayEntry\Next
        ; Eintrag gibts noch nicht
        ProcedureReturn 0
      EndIf
      *cur = *IArrayEntry\Next\IArray
    EndIf
  Until Not Index
  
  ; Wert lesen
  ProcedureReturn *IArrayEntry\Value
EndProcedure

; Freigabe Procedure ist hoch-rekursiv, kann etwas länger dauern...
Procedure _IArray_FreeSub(*IData.IArray_Holder)
  For i = 0 To 9
    If *IData\Entry[i]\Next
      _IArray_FreeSub(@*IData\Entry[i]\Next\IArray)
    EndIf
  Next
  FreeMemory(*IData)
EndProcedure

; Array freigeben
Procedure IArray_Free(*IArray.IArray)
  _IArray_FreeSub(*IArray)
EndProcedure

#SCNT = 10000000
#CNT = 20000000
IArray = New_IArray()

t = ElapsedMilliseconds()
For i = #SCNT To #CNT
  IArray_Set(IArray, i, i*2)
Next
t1 = ElapsedMilliseconds()-t

t = ElapsedMilliseconds()
For i = #SCNT To #CNT
  IArray_Get(IArray, i)
Next
t2 = ElapsedMilliseconds()-t

t = ElapsedMilliseconds()
IArray_Free(IArray)
t3 = ElapsedMilliseconds()-t

MessageRequester("test", "Gesamt: Einträge: " + Str(#CNT-#SCNT) + Chr(13) + "Schreiben & Erstellen: Zugriffe: " + StrF((#CNT-#SCNT)/t1*1000, 2) + "/Sek" + Chr(13) + "Lesen: Zugriffe: " + StrF((#CNT-#SCNT)/t2*1000, 2) + "/Sek" + Chr(13) + "Aufräumen: " + StrF(t3/1000, 2) + " sek")
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

x86 hat geschrieben:---------------------------
test
---------------------------
Gesamt: Einträge: 10000000
Schreiben & Erstellen: Zugriffe: 2433090.00/Sek
Lesen: Zugriffe: 2510040.25/Sek
Aufräumen: 0.16 sek
---------------------------
OK
---------------------------
x64 hat geschrieben:---------------------------
test
---------------------------
Gesamt: Einträge: 10000000
Schreiben & Erstellen: Zugriffe: 1464557.75/Sek
Lesen: Zugriffe: 1523693.38/Sek
Aufräumen: 0.16 sek
---------------------------
OK
---------------------------
Hab aber nur getestet obs läuft, ob die Ergebnisse korrekt sind kann ich
nicht sagen, dafür müßte ich erstmal drüber Nachdenken wofür das gut ist :mrgreen:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
coder
Beiträge: 204
Registriert: 25.09.2005 17:53
Computerausstattung: Intel Core2Quad Q8200 @ 2.33GHz
ASUS P5Q3, 2GB DDR3-1066 RAM, ATi Raedeon HD 4850
Wohnort: Deutschland
Kontaktdaten:

Beitrag von coder »

Sehr interressant :allright:
Besonders nützlich für die Verwaltung von Network-Clients auf einen Server über die Client-IDs
Windows 7 x64 | PureBasic 4.60 4.50 4.02
Ja verdammt, meine Eltern wohnen immer noch bei mir!
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

das müßte man in der Verwendbarkeit und Performanz mal mit Hashtables vergleichen...
oder entspricht das einem Hashtabel von der Funktionalität her?
damit kenn ich mich leider zu wenig aus.


(btw: Index, Pl. Indices bzw. Indizes, V. indizieren)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
coder
Beiträge: 204
Registriert: 25.09.2005 17:53
Computerausstattung: Intel Core2Quad Q8200 @ 2.33GHz
ASUS P5Q3, 2GB DDR3-1066 RAM, ATi Raedeon HD 4850
Wohnort: Deutschland
Kontaktdaten:

Beitrag von coder »

Naja, im Prinzip macht es ja das gleiche wie eine HashTable...
Ich versteh bloß noch nicht so richt, wie das hier funktioniert...
Windows 7 x64 | PureBasic 4.60 4.50 4.02
Ja verdammt, meine Eltern wohnen immer noch bei mir!
Benutzeravatar
Josef Sniatecki
Beiträge: 657
Registriert: 02.06.2008 21:29
Kontaktdaten:

Beitrag von Josef Sniatecki »

Sehr interessant. Habe bisher nur mit Strings sowas ähnliches wie
ein intelligentes Array gemacht: http://www.purebasic.fr/german/viewtopic.php?t=17083

Habe also für den Zugriff auf ein Item namens "ABC" immer "A","B","C"
gemacht.
Mit Zahlen ist das natürlich ein wenig anders (und schwerer).
PB 4.61 | Windows Vista - 32Bit
Homepage

"Wahrlich es ist nicht das Wissen, sondern das Lernen, nicht das Besitzen sondern das Erwerben, nicht das Dasein, sondern das Hinkommen, was den grössten Genuss gewährt." - Carl Friedrich Gauß
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Als Vergleich mal eine einfache stl map
---------------------------
test
---------------------------
Gesamt: Einträge: 10000000
Schreiben & Erstellen: Zugriffe: 1868809.63/Sek
Lesen: Zugriffe: 4006410.25/Sek
Aufräumen: 0.00 sek
---------------------------
OK
---------------------------
Zuletzt geändert von edel am 07.04.2009 15:39, insgesamt 1-mal geändert.
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Das Verfahren könnte ggf. noch nicht unwesentlich beschleunigt werden, wenn nicht das Dezimalsystem verwendet wird, sondern bspw. das Hexadezimalsystem, also wenn jede Ebene in 16 Unterebenen verzweigen kann. Dann spart man sich die ganzen Divisionen mit 10 und kann stattdessen einfach mit "ID & $F" bzw. "ID >> 4" verzweigen.

Trotzdem denke ich mal, dass eine auf Zahlen optimierte Hashtable noch deutlich schneller ist.
!UD2
Antworten