Cấp bậc tác giả:

TRAINING

Sự khác nhau giữa foreach và for

Được viết bởi webmaster ngày 03/09/2013 lúc 10:52 AM
Có hai loại lập trình viên. Người viết code để làm và người muốn viết code tốt. Ở đây chúng ta nhận được một câu hỏi lớn. Code tốt là gì? Code tốt xuất phát từ thực hành lập trình tốt. Thực hành lập trình tốt là gì?
  • 0
  • 18234

Sự khác nhau giữa foreach và for

Giới thiệu
Có hai loại lập trình viên. Người viết code để làm và người muốn viết code tốt. Ở đây chúng ta nhận được một câu hỏi lớn. Code tốt là gì? Code tốt xuất phát từ thực hành lập trình tốt. Thực hành lập trình tốt là gì? Trên thực tế, mục tiêu của tôi ở đây không phải là để nói về thực hành lập trình tốt (tôi đang lập kế hoạch để viết code sắp tới!), Chứ không phải để nói chuyện nhiều hơn về cách viết một cái gì đó sẽ hiệu quả hơn. Tôi chỉ xem xét sâu hơn trong hai tuyến được sử dụng phổ biến hiện nay, và sự khác biệt của chúng trong các khía cạnh về hiệu suất.

Background
Phải làm quen với IL và assembly. Một số kiến ​​thức của JIT cũng cần thiết để hiểu điều gì đang xảy ra.

Sử dụng mã
Tôi sẽ ví dụ một phần nhỏ mã của 2 vòng lặp phổ biến là for và foreach. Chúng ta sẽ xem xét một số mã và sẽ thấy những gì nó làm được, chi tiết hơn về các chức năng.

FOR

int[] myInterger = new int[1];
int total = 0;
for(int i = 0; i < myInterger.Length; i++)
{
    total += myInterger[i];
}

FOREACH

int[] myInterger = new int[1];
int total = 0;
foreach(int i in myInterger) 
{
    total += i;
}

Cả hai mã sẽ tạo ra kết quả tương tự. foreach được sử dụng trên đầu trang của collections để thông qua trong khi for có thể được sử dụng trên bất cứ đâu. Tôi sẽ không giải thích gì về các mã. Trước khi đi vào sâu hơn, tôi nghĩ rằng các bạn đã quen thuộc với ILDASM được sử dụng để tạo ra mã IL, và công cụ CorDbg mà thường được sử dụng để tạo ra mã biên dịch JIT.

Mã IL xuất bởi biên dịch C # được tối ưu hóa đến một số mở rộng, trong khi để lại một số phần đến JIT. Dù sao, điều này không thực sự quan trọng đối với chúng ta. Vì vậy, khi chúng ta nói về việc tối ưu hóa, có hai điều chúng ta phải xem xét. Đầu tiên là biên dịch C # và thứ hai là JIT.

Vì vậy, thay vì tìm kiếm sâu hơn vào mã IL, chúng ta sẽ thấy thêm về mã được phát ra bởi JIT. Đó là đoạn code sẽ chạy trên máy tính của chúng ta. Bây giờ ta đang sử dụng bộ xử lý AMD Athlon 1900 +. Mã này rất phụ thuộc vào phần cứng của chúng ta. Vì vậy, những gì bạn có thể nhận được từ máy tính của bạn có thể khác với tôi đến một số mở rộng. Dù sao, các thuật toán sẽ không thay đổi nhiều.

Trong khai báo biến, foreach có năm khai báo biến (ba số nguyên Int32 và hai mảng Int32) trong khi for chỉ có ba (hai số nguyên Int32 và một mảng Int32). Khi nó vào thông qua vòng lặp, foreach sao chép các mảng hiện tại đến một for hoạt động mới. Trong khi for không quan tâm phần đó.

Ở đây, tôi sẽ chỉ vào sự khác biệt chính xác giữa các mã.

FOR
Instruction                           Effect
cmp     dword ptr [eax+4],0           i<myInterger.Length
jle     0000000F
mov     ecx,dword ptr [eax+edx*4+8]   total += myInterger[i]
inc     edx                           ++i
cmp     esi,dword ptr [eax+4]         i<myInterger.Length
jl      FFFFFFF8

Tôi sẽ giải thích những gì đang xảy ra ở đây. ESI đăng ký giữ giá trị và chiều dài của mảng myInteger được so sánh ở hai đoạn. Đầu tiên được thực hiện chỉ một lần để kiểm tra điều kiện và nếu vòng lặp có thể tiếp tục, giá trị được thêm vào. Đối với các vòng lặp, nó được thực hiện ở đoạn thứ hai. Bên trong vòng lặp, nó được tối ưu hóa tốt và như đã giải thích, công việc được thực hiện tối ưu hóa hoàn hảo.

FOREACH
Instruction                           Effect
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length 
jb      00000009
mov     eax,dword ptr [ebx+esi*4+8] 
mov     dword ptr [ebp-0Ch],eax  
mov     eax,dword ptr [ebp-0Ch]
add     dword ptr [ebp-8],eax          total += i
inc     esi                            ++i
cmp     esi,dword ptr [ebx+4]          i<myInterger.Length
jl      FFFFFFE3

Bất cứ ai cũng sẽ nói rằng cả hai đều không giống nhau. Nhưng chúng ta sẽ xem xét lý do tại sao nó khác với FOR. Lý do chính của sự khác biệt là cả hai đều khác nhau hiểu bởi trình biên dịch. Các thuật toán chúng đang sử dụng là khác nhau. Nó đang làm điều tương tự một lần nữa và một lần nữa không có lý do!
cmp                    esi,dword ptr [ebx+4]   
jl                         FFFFFFE3
cmp                    esi,dword ptr [ebx+4]
Nó cũng sử dụng báo cáo di chuyển không cần thiết làm giảm hiệu suất của mã. foreach được nghĩ rằng tất cả mọi thứ như collection và đối xử với chúng như collection. Tôi cảm thấy, sẽ làm giảm hiệu suất công việc.

Vì vậy, tôi cảm thấy rằng nếu bạn đang có kế hoạch để viết mã hiệu suất cao mà không phải là collection, sử dụng cho FOR. Ngay cả đối với collection, foreach có thể nhìn thuận tiện khi sử dụng, nhưng nó không phải là hiệu quả. Vì vậy, tôi đề nghị tất cả mọi người sử dụng FOR thay vì FOREACH bất kỳ lúc nào.

Kết luận

Trên thực tế, tôi đã làm một nghiên cứu nhỏ về vấn đề hiệu suất của các mã chủ yếu trên .NET. Tôi thấy rằng thực sự phải biết làm thế nào để JIT hoạt động và gỡ lỗi các mã được tạo ra bởi trình biên dịch JIT. Phải mất một thời gian để hiểu được mã.

Nguồn bài viết: DOTNET.VN

BÌNH LUẬN BÀI VIẾT

Bài viết mới nhất

LIKE BOX

Bài viết được xem nhiều nhất

HỌC HTML