2013-04-26 9 views
5

Una domanda su un pezzo di codice lua è emersa durante una revisione del codice che avevo recentemente. Il codice in questione è l'eliminazione di un cache e reinizializzazione con alcuni dati:È meglio impostare una tabella per svuotare o impostare tutti gli elementi di una tabella su zero?

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

-- reinitialize here 

C'è qualche ragione il loop di cui sopra non deve essere sostituito con questo?

fileTable = { } 

-- reinitialize here 
+0

Per ridurre le allocazioni di memoria - operazioni di deallocazione? –

+3

Oltre ai problemi di prestazioni descritti nella risposta ... se la tabella viene utilizzata da altre parti del programma con altri nomi, il ciclo è assolutamente necessario. Se si esegue l'assegnazione, si perde semplicemente il collegamento all'oggetto tabella e gli altri nomi puntano ancora alla stessa tabella completa, mentre il ciclo lo cancella per tutti. –

risposta

2

È dovuto al ridimensionamento tabella ridimensionamento/rehash. Quando viene creata una tabella, è vuota. Quando si inserisce un elemento, viene eseguito un rehash e la dimensione della tabella viene aumentata a 1. Lo stesso accade quando si inserisce un altro elemento. La regola è che una tabella viene generata ogni volta che lo spazio non è sufficiente (in una matrice o in una parte hash) per contenere un altro elemento. La nuova dimensione è la più piccola potenza di 2 che può accogliere il numero richiesto di elementi. Per esempio. rehash si verifica quando si inserisce un elemento, se una tabella contiene 0, 1, 2, 4, 8, ecc. elemnts.

Ora la tecnica che si sta descrivendo consente di risparmiare quei rihashes, poiché Lua non riduce le tabelle. Quindi, quando si hanno frequenti operazioni di fill/flush table, è meglio (per quanto riguarda le prestazioni) farlo nel proprio esempio piuttosto che creare una tabella vuota.

Aggiornamento:

ho messo un po 'di test:

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 

I risultati sono interessanti smettere. L'esecuzione di test(4, 10000000) su Lua 5.1 ha dato 7 secondi per zero e 10 secondi per vuoti. Per le tabelle più grandi di 32 elementi, la versione vuota era più veloce (più grande è il tavolo, maggiore è la differenza). test(128, 400000) ha dato 9 secondi per nils e 5 secondi per vuoti.

Ora su LuaJIT, dove le operazioni alloc e gc sono relativamente lente, l'esecuzione di test(1024, 1000000) ha dato 3 secondi per i nils e 7 secondi per i vuoti.

P.S. Notare la differenza di prestazione tra Lua e LuaJIT. Per 1024 tabelle di elementi, Lua ha fatto 100.000 iterazioni di prova in circa 20 secondi, LuaJIT ha fatto 1.000.000 di iterazioni in 10 secondi!

+0

L'uso di un nome di variabile come 'tabella' non è consigliabile. Rompe altre funzioni come 'table.concat' :) – hjpotter92

+0

@hjpotter, solo in quella funzione, poiché è un locale.Non è consigliabile, se non ne sei a conoscenza (scope). –

0

Assegnazione di una nuova tabella è un'operazione costosa in Lua (che è vero per qualsiasi allocazione degli oggetti in praticamente qualsiasi linguaggio dinamico). Inoltre, costantemente "perdere" di recente creato su GC metterà a dura prova le prestazioni, oltre alla memoria, dato che ogni tabella creata rimarrà in memoria fino a quando GC arriverà effettivamente a reclamarlo.

La tecnica nell'esempio traduce quegli svantaggi per il tempo richiesto per rimuovere esplicitamente tutti gli elementi nella tabella. Questo sarà sempre un risparmio di memoria e, a seconda della quantità di elementi, potrebbe spesso essere anche un miglioramento delle prestazioni.

4

A meno che non abbiate prove contrarie, fareste meglio a fidarvi della garbage collection di Lua: create un nuovo tavolo vuoto quando ne avete bisogno.

Problemi correlati