2016-07-20 14 views
6

Tôi đã viết một lớp C# có tên là "Danh sách Danh sách tăng gấp đôi" với một số dữ liệu (không quan trọng dữ liệu là gì, bây giờ nó chỉ là rác) :), cho mục đích thử nghiệm:Tại sao sử dụng Tuple nhanh hơn một Danh sách trong ví dụ này?

đây là mã:

class test 
    { 
    public test() 
    { 
     _myListOfList = new List<List<double>>(1000000); 
    } 
    public void Run() 
    { 
     for (int i = 0; i < _myListOfList.Capacity; i++) 
     { 
      _myListOfList.Add(
       new List<double>(3) { i, 10*i, 100*i} 
       ); //Populate the list with data 
     } 
    } 

    private List<List<double>> _myListOfList; 
} 

tôi đã so sánh tốc độ thực hiện của mã này như sau: (thay thế Danh sách đôi bởi một tuple)

class test 
    { 
    public test() 
    { 
     _myListOfTuple = new List<Tuple<double, double, double>>(1000000); 
    } 
    public void Run() 
    { 
     for (int i = 0; i < _myListOfTuple.Capacity; i++) 
     { 
      _myListOfTuple.Add(
       new Tuple<double, double, double>(i, 10 * i, 100 * i) 
       ); //Populate the list with data 
     } 
    } 

    private List<Tuple<double, double, double>> _myListOfTuple; 
} 

Hóa ra rằng việc sử dụng các tuple dường nhanh hơn đáng kể. Tôi chạy đoạn mã này để kích thước Danh sách khác nhau (từ 200.000 yếu tố -> 5 triệu yếu tố trong danh sách) và đây là kết quả tôi nhận được:

graph

tôi có thể không thực sự có được quanh đầu tôi thế này. Làm thế nào tôi có được một sự khác biệt đáng kể? Sử dụng một Tuple lưu trữ đối tượng cùng loại (gấp đôi ở đây) không có ý nghĩa nhiều. Tôi muốn sử dụng một List/array để làm điều đó: tôi đang làm gì sai? Có cách nào tôi có thể làm cho trường hợp # 1 chạy nhanh/nhanh hơn trường hợp # 2 không?

Cảm ơn!

+2

Tại sao điều này lại đáng ngạc nhiên? Phải mất nhiều công việc hơn để xử lý việc lưu trữ một số lượng lớn các đối tượng tùy ý để lưu trữ chính xác 3 đối tượng. – Servy

+0

Chi phí đầu tư. Đối với một điều, bao nhiêu không gian bạn sẽ mong đợi một tuple tăng gấp đôi chiếm so với một danh sách? Bạn sẽ mong đợi họ có nội dung gì cho từng loại? –

+1

thu nhỏ thậm chí sự khác biệt nhỏ lên đủ khiến chúng trông lớn hơn .. – TaW

Trả lời

7

Có sự khác biệt giữa new Tuple<double, double, double>(i, 10 * i, 100 * i)new List<double>(3) { i, 10*i, 100*i}.

Người đầu tiên là siêu đơn giản - chỉ cần 3 nhiệm vụ:

public Tuple(T1 item1, T2 item2, T3 item3) { 
    m_Item1 = item1; 
    m_Item2 = item2; 
    m_Item3 = item3; 
} 

Điều thứ hai là thực sự biến đổi bởi trình biên dịch thành 3 Add phương pháp gọi:

var temp = new List<double>(3); 
temp.Add(i); 
temp.Add(10 * i); 
temp.Add(100 * i); 

Add là nhiều hơn chỉ là một bài tập:

public void Add(T item) { 
    if (_size == _items.Length) EnsureCapacity(_size + 1); 
    _items[_size++] = item; 
    _version++; 
} 

Mã khác t o chạy, thực thi chậm hơn. Khá đơn giản ..

+0

Cảm ơn một loạt câu trả lời của bạn .. nó có ý nghĩa rất nhiều! Như @Tigran đã đề xuất, tôi đã thay thế Danh sách bằng một mảng (int mới [3] {i, 10 * i, 100 * i}) và tôi nhận được kết quả rất giống về tốc độ :) – harveyAJ

2

Như đã đề cập trong câu trả lời của @ Marcin đúng là ngay cả khi khởi tạo List<T> bằng danh sách khởi tạo IL vẫn có chức năng Add() bên trong, ngay cả khi bạn chỉ định ban đầu, trong khi xây dựng, Capacity của danh sách. Như bạn đã làm trong ví dụ của bạn.

Có cách nào tôi có thể làm cho trường hợp số 1 chạy nhanh/nhanh hơn trường hợp # 2 không?

Các giải pháp khả thi có thể giao trực tiếp cho các thành viên:

list[0] = 
list[1] = 
list[2] = 

Trong trường hợp này IL trông như thế này:

IL_0000: ldc.i4.3  
IL_0001: newobj  System.Collections.Generic.List<System.Double>..ctor 
IL_0006: stloc.0  // list 
IL_0007: ldloc.0  // list 
IL_0008: ldc.i4.0  
IL_0009: ldc.r8  00 00 00 00 00 00 F0 3F 
IL_0012: callvirt System.Collections.Generic.List<System.Double>.set_Item 
IL_0017: ldloc.0  // list 
IL_0018: ldc.i4.1  
IL_0019: ldc.r8  00 00 00 00 00 00 24 40 
IL_0022: callvirt System.Collections.Generic.List<System.Double>.set_Item 
IL_0027: ldloc.0  // list 
IL_0028: ldc.i4.2  
IL_0029: ldc.r8  00 00 00 00 00 00 59 40 
IL_0032: callvirt System.Collections.Generic.List<System.Double>.set_Item 
IL_0037: ret 

set_Item là nhanh hơn khi đó là một nhiệm vụ đơn giản.

Hoặc sử dụng đơn giản Array. Hiệu suất nên trở nên tốt hơn. Tuy nhiên, với những thứ như vậy, như tốc độ A vs B, câu trả lời thực sự chỉ có sau khi đo lường cụ thể.

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