2009-06-23 13 views
20

Interlocked.Increment(ref x) nhanh hơn hoặc chậm hơn x++ cho ints và longs trên các nền tảng khác nhau?Hiệu suất của Interlocked.Increment

+0

Như những người khác chỉ ra, nó không phải là điều tương tự. Điều đó nói rằng, theo http://msdn.microsoft.com/en-us/magazine/cc163726.aspx một Interlocked.Increment mất một số 14nS (hoặc khoảng 71'000'000 mỗi giây) vì vậy tôi sẽ không lo lắng nhiều Về hiệu suất – smirkingman

+0

Lồng vào nhau.Giải pháp được dự định sẽ được sử dụng trong các môi trường chủ đề – EProgrammerNotFound

Trả lời

37

Nó chậm hơn vì nó tác động đến nguyên tử và nó hoạt động như một rào cản bộ nhớ, loại bỏ khả năng sắp xếp lại bộ nhớ của bộ xử lý truy cập xung quanh hướng dẫn.

Bạn nên sử dụng Interlocked.Increment khi bạn muốn hành động là nguyên tử trên trạng thái có thể được chia sẻ giữa các luồng - nó không có ý định thay thế hoàn toàn cho x ++.

3

Nó sẽ luôn chậm hơn vì nó phải thực hiện khóa bus CPU so với việc cập nhật thanh ghi. Tuy nhiên, các CPU hiện đại đạt được hiệu suất gần như đăng ký nên nó không đáng kể ngay cả trong thời gian thực xử lý.

+3

Trong khi CPU X86 thực hiện một buslock trong các hoạt động liên khóa, một buslock không được yêu cầu bởi tất cả các CPU cung cấp các hoạt động liên khóa. Một số CPU có khả năng ký rằng họ đã dành riêng một dòng bộ nhớ cache duy nhất và có thể thực hiện các hoạt động liên khóa trên bộ nhớ đệm đó mà không có buslock. – Adisak

4

Tốc độ chậm hơn. Tuy nhiên, đó là cách tổng quát nhất mà tôi biết để đạt được an toàn luồng trên các biến vô hướng.

+1

'volatile' hoạt động tốt hơn trên vô hướng, nhưng có nhược điểm là yêu cầu thực hành mã hóa tốt để sử dụng tốt. – Abel

+2

Cẩn thận với dễ bay hơi; một số kiến ​​trúc bộ xử lý (x86/x64) có khả năng sắp xếp lại quyền truy cập vào bộ nhớ, bất kể bộ nhớ đó được đánh dấu là dễ bay hơi cho trình biên dịch hay không. –

6

Hãy suy nghĩ về nó một lúc và bạn sẽ nhận ra cuộc gọi Increment không thể nhanh hơn ứng dụng đơn giản của toán tử gia tăng. Nếu nó được, sau đó thực hiện của trình biên dịch của nhà điều hành tăng sẽ gọi Increment nội bộ, và họ muốn thực hiện như vậy.

Nhưng, như bạn có thể thấy bằng cách thử nghiệm nó cho chính mình, họ không thực hiện như vậy.

Hai tùy chọn có mục đích khác nhau. Sử dụng toán tử gia tăng nói chung. Sử dụng Increment khi bạn cần hoạt động là nguyên tử và bạn chắc chắn rằng tất cả người dùng khác của biến đó cũng đang sử dụng các hoạt động liên khóa. (Nếu chúng không phải tất cả hợp tác, thì nó không thực sự hữu ích.)

+0

Không, nó sẽ không - Interlocked.Increment không thể được gọi trên một thuộc tính, trong khi toán tử ++ có thể. Do đó, ++ sẽ không thể gọi nó. – SLaks

+0

Để chính xác hơn, Increment mất một ref int (hoặc dài); ++ mất một int không-ref (hoặc dài) – SLaks

+3

Trình biên dịch chắc chắn có thể thực hiện ++ qua Increment. Nó sẽ không được thực hiện với một lệnh "gọi" đơn giản, nhưng nó có thể được thực hiện bằng cách sử dụng một trình giới thiệu tạm thời bởi trình biên dịch. Vấn đề là trình biên dịch sử dụng phương thức có sẵn để tăng số lượng; nếu có cái gì đó nhanh hơn, trình biên dịch sẽ sử dụng nó thay thế. –

12

Theo kinh nghiệm của chúng tôi, InterlockedIncrement() và cộng sự trên Windows là những tác động khá đáng kể. Trong một trường hợp mẫu, chúng tôi có thể loại bỏ khóa liên động và sử dụng ++/- thay vào đó. Điều này một mình giảm thời gian chạy từ 140 giây xuống còn 110 giây. Phân tích của tôi là khóa liên động buộc một vòng tròn bộ nhớ (nếu không thì các lõi khác có thể nhìn thấy nó như thế nào?). Bộ nhớ cache đọc/ghi L1 khoảng 10 chu kỳ đồng hồ, nhưng bộ nhớ đọc/ghi nhiều hơn 100.

Trong trường hợp mẫu này, tôi ước tính số hoạt động tăng/giảm khoảng 1 tỷ. Vì vậy, trên một CPU 2Ghz này là một cái gì đó giống như 5 giây cho ++/-, và 50 giây cho khóa liên động. Lây lan sự khác biệt trên một số chủ đề, và nó gần 30 giây.

+5

Micrsoft nói: InterlockedIncrement được đo bằng cách lấy 36-90 chu kỳ trong http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650(v=vs.85).aspx – Lothar

+1

36 âm thanh phù hợp với không bị cản trở hoạt động, tôi đang đo khoảng 120 lần cho hoạt động gây tranh cãi nặng nề trên Core i7, nhưng có lẽ tôi đã làm hỏng nó? Dù sao, "interlock buộc một vòng tròn bộ nhớ (nếu không thì các lõi khác có thể nhìn thấy nó như thế nào?). L1 cache đọc/ghi là khoảng 10 chu kỳ đồng hồ ..." - đủ để đánh dấu trang đó đã thay đổi và chỉ tuôn ra từ L1 sang bộ nhớ nếu một lõi khác cần nhìn thấy nó, vì vậy hoạt động không được kiểm soát có thể gần hơn với 10 đầu của phổ (ở 36) thay vì 100 + .... –

4

tôi kiểm tra Biến:

dễ bay hơi: 65.174.400

khóa: 62.428.600

đan cài: 113.248.900

TimeSpan span = TimeSpan.FromSeconds(5); 

object syncRoot = new object(); 
long test = long.MinValue; 

Do(span, "volatile",() => { 

    long r = Thread.VolatileRead(ref test); 

    r++; 

    Thread.VolatileWrite(ref test, r); 
}); 

Do(span, "lock",() => 
{ 
    lock (syncRoot) 
    { 
     test++; 
    } 
}); 

Do(span, "interlocked",() => 
{ 
    Interlocked.Increment(ref test); 
}); 
+2

Có gì 'Do'? – SLaks

+0

Nó chạy phương pháp n lần cho đến khi thời gian đã đạt đến – MastsrOfDesaster

+3

Vì vậy, chờ đợi, nhiều hơn là tốt hơn trong trường hợp này? Bạn có thể vui lòng chỉ định số liệu của bạn là gì không? –