2013-04-26 4 views
5

Eine Frage zu einem Stück Lua-Code kam während eines Code-Reviews auf, den ich kürzlich hatte. Der betreffende Code leert einen Cache und neu initialisiert es mit einigen Daten:Ist es besser, eine Tabelle leer zu setzen oder alle Elemente einer Tabelle auf null zu setzen?

for filename,_ in pairs(fileTable) do 
    fileTable[filename] = nil 
end 

-- reinitialize here 

Gibt es einen Grund, warum die obige Schleife sollte nicht mit dieser ersetzt werden?

fileTable = { } 

-- reinitialize here 
+0

Um Speicherzuweisung-Freigabe-Operationen zu reduzieren? –

+3

Zusätzlich zu den in der Antwort beschriebenen Leistungsproblemen ... wenn die Tabelle von anderen Teilen des Programms unter anderen Namen verwendet wird, ist die Schleife unbedingt erforderlich. Wenn Sie die Zuweisung vornehmen, verlieren Sie einfach die Verbindung zum Tabellenobjekt und die anderen Namen zeigen immer noch auf die gleiche vollständige Tabelle, während die Schleife sie für alle löscht. –

Antwort

2

Es ist aufgrund der Tabelle Resize/Rehash Overhead. Wenn eine Tabelle erstellt wird, ist sie leer. Wenn Sie ein Element einfügen, findet eine erneute Vergrößerung statt und die Tabellengröße wird auf 1 erhöht. Dasselbe geschieht, wenn Sie ein anderes Element einfügen. Die Regel besteht darin, dass eine Tabelle immer dann vergrößert wird, wenn nicht genügend Speicherplatz vorhanden ist (entweder in einem Array oder einem Hash-Teil), um ein anderes Element aufzunehmen. Die neue Größe ist die kleinste Potenz von 2, die die erforderliche Anzahl von Elementen aufnehmen kann. Z.B. rehash tritt auf, wenn Sie ein Element einfügen, wenn eine Tabelle 0, 1, 2, 4, 8 usw. Elemente enthält.

Jetzt spart die Technik, die Sie beschreiben, diese Neuauflagen, da Lua die Tabellen nicht verkleinert. Wenn Sie also häufig Fill-/Flush-Tabellenoperationen durchführen, ist es besser (in der Leistung), es wie in Ihrem Beispiel zu tun, als eine leere Tabelle zu erstellen.

Update:

Ich habe einen kleinen Test setzen:

local function rehash1(el, loops) 
    local table = {} 
    for i = 1, loops do 
     for j = 1, el do 
      table[j] = j 
     end 
     for k in ipairs(table) do table[k] = nil end 
    end 
end 

local function rehash2(el, loops) 
    for i = 1, loops do 
     local table = {} 
     for j = 1, el do 
      table[j] = j 
     end 
    end 
end 


local function test(elements, loops) 
    local time = os.time(); 
    rehash1(elements, loops); 
    local time1 = os.time(); 
    rehash2(elements, loops); 
    local time2 = os.time(); 

    print("Time nils: ", tostring(time1 - time), "\n"); 
    print("Time empty: ", tostring(time2 - time1), "\n"); 

end 

Ergebnisse sind beenden interessant. Laufen test(4, 10000000) auf Lua 5.1 gab 7 Sekunden für Nils und 10 Sekunden für Leergut. Bei Tabellen mit mehr als 32 Elementen war die leere Version schneller (je größer die Tabelle, desto größer der Unterschied). test(128, 400000) gab 9 Sekunden für Nils und 5 Sekunden für Leergut.

Jetzt auf LuaJIT, wo Alloc und GC-Operationen relativ langsam sind, gab test(1024, 1000000) 3 Sekunden für Nils und 7 Sekunden für Leergut.

P.S. Beachten Sie den schieren Leistungsunterschied zwischen reinem Lua und LuaJIT. Für 1024 Elementtabellen hat Plain Lua 100.000 Testiterationen in etwa 20 Sekunden durchgeführt, LuaJIT hat 1.000.000 Iterationen über 10 Sekunden gemacht!

+0

Die Verwendung eines Variablennamens als 'Tabelle' ist nicht ratsam. Es bricht andere Funktionen wie 'table.concat' :) – hjpotter92

+0

@hjpotter, Nur in dieser Funktion, da es ein lokaler ist.Es ist nicht ratsam, wenn Sie sich dessen nicht bewusst sind (Umfang). –

0

eine neue Tabelle Zuweisung ist ein kostspieliger Vorgang in Lua (die für jede Objektzuordnung in so ziemlich jede dynamischen Sprache wahr ist). Darüber hinaus wird das ständige "Verlieren" von neu erstellten GCs die Performance sowie den Speicher zusätzlich belasten, da alle erstellten Tabellen immer noch im Speicher verbleiben, bis GC sie tatsächlich beansprucht.

Technik in Ihrem Beispiel handelt diese Nachteile für die Zeit benötigt explizit alle Elemente in der Tabelle zu entfernen. Dies wird immer eine Speicherersparnis sein und, abhängig von der Anzahl der Elemente, oft auch eine Leistungsverbesserung.

4

Wenn Sie keine anderen Beweise haben, sollten Sie Lua's Garbage Collection besser vertrauen: Erstellen Sie einfach eine neue, leere Tabelle, wenn Sie sie brauchen.

Verwandte Themen