2013-04-26 25 views
5

Một câu hỏi về một đoạn mã lua đã xuất hiện trong quá trình xem xét mã tôi đã có gần đây. Mã đang đề cập đang xóa bộ nhớ cache và khởi động lại bộ nhớ đó bằng một số dữ liệu:Tốt hơn là đặt bảng để trống hoặc đặt tất cả các phần tử của bảng thành không?

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

-- reinitialize here 

Có lý do nào không nên thay thế vòng lặp này?

fileTable = { } 

-- reinitialize here 
+0

Để giảm hoạt động phân bổ cấp phát bộ nhớ? –

+3

Ngoài các vấn đề hiệu suất được mô tả trong câu trả lời ... nếu bảng được sử dụng bởi các phần khác của chương trình dưới các tên khác, vòng lặp là hoàn toàn cần thiết. Nếu bạn làm nhiệm vụ bạn chỉ cần mất liên kết đến đối tượng bảng và các tên khác vẫn trỏ đến cùng một bảng đầy đủ, trong khi vòng lặp xóa nó cho tất cả mọi người. –

Trả lời

2

Đó là do thay đổi kích thước bảng/phục hồi trên không. Khi một bảng được tạo, nó sẽ trống. Khi bạn chèn một phần tử, quá trình rehash diễn ra và kích thước bảng được tăng lên 1. Điều tương tự cũng xảy ra, khi bạn chèn phần tử khác. Quy tắc là một bảng được phát triển bất cứ khi nào không có đủ không gian (trong mảng hoặc phần băm) để giữ một phần tử khác. Kích thước mới là công suất nhỏ nhất của 2 có thể chứa số lượng phần tử được yêu cầu. Ví dụ. rehash xảy ra khi bạn chèn một phần tử, nếu một bảng chứa 0, 1, 2, 4, 8, vv elemnts.

Bây giờ kỹ thuật bạn mô tả sẽ lưu các lần khôi phục đó, vì Lua không thu nhỏ bảng. Vì vậy, khi bạn đã thường xuyên điền/hoạt động bảng tuôn ra nó tốt hơn (hiệu suất khôn ngoan) để làm điều đó như trong ví dụ của bạn hơn để tạo ra một bảng trống.

Cập nhật:

Tôi đã đưa ra một thử nghiệm nhỏ:

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 

Kết quả được bỏ thú vị. Chạy test(4, 10000000) trên Lua 5.1 cho 7 giây đối với nils và 10 giây cho trống. Đối với các bảng lớn hơn 32 phần tử, phiên bản trống sẽ nhanh hơn (bảng càng lớn, chênh lệch càng lớn). test(128, 400000) cho 9 giây cho nils và 5 giây cho trống.

Bây giờ trên LuaJIT, nơi phân bổ và hoạt động gc tương đối chậm, chạy test(1024, 1000000) cho 3 giây cho nils và 7 giây cho trống.

P.S. Chú ý sự khác biệt hiệu suất tuyệt đối giữa LuaJIT thuần túy và LuaJIT. Với 1024 bảng phần tử, Lua đã thực hiện 100.000 lần thử nghiệm trong khoảng 20 giây, LuaJIT đã thực hiện 1.000.000 lần lặp trong 10 giây!

+0

Sử dụng tên biến là 'bảng' không được khuyến khích. Nó phá vỡ các chức năng khác như 'table.concat' :) – hjpotter92

+0

@hjpotter, Chỉ trong hàm đó, vì nó là một địa phương.Nó không được khuyến khích, nếu bạn không nhận thức được nó (phạm vi). –

0

Phân bổ bảng mới là hoạt động tốn kém trong Lua (điều này đúng với bất kỳ phân bổ đối tượng nào bằng ngôn ngữ động). Ngoài ra, liên tục "mất" mới được tạo ra để GC sẽ đặt thêm căng thẳng về hiệu suất, cũng như bộ nhớ, vì mỗi bảng được tạo ra sẽ vẫn còn trong bộ nhớ cho đến khi GC thực sự đến để yêu cầu nó.

Kỹ thuật trong ví dụ của bạn giao dịch những bất lợi đó cho thời gian cần thiết để loại bỏ rõ ràng tất cả các phần tử trong bảng. Điều này sẽ luôn luôn là một bộ nhớ tiết kiệm và, tùy thuộc vào số lượng các yếu tố, thường có thể là một cải tiến hiệu suất là tốt.

4

Trừ khi bạn có bằng chứng khác, bạn nên tin tưởng vào bộ sưu tập rác của Lua: chỉ cần tạo một bảng mới, trống khi bạn cần.

Các vấn đề liên quan