2012-01-04 36 views
27

Tôi có một máy chủ xử lý nhiều kết nối ổ cắm đến và tạo ra 2 luồng khác nhau lưu trữ dữ liệu ở định dạng XML.Khi nào nên sử dụng dây khóa trong C#?

Tôi đã sử dụng câu lệnh lock cho an toàn chủ đề gần như trong mọi trình xử lý sự kiện được gọi là asyncronously và trong 2 chuỗi trong các phần mã khác nhau. Đáng buồn thay bằng cách sử dụng phương pháp này, ứng dụng của tôi làm chậm đáng kể.

Tôi đã cố gắng không sử dụng lock và máy chủ rất nhanh trong việc thực thi, ngay cả khi lưu trữ tệp có vẻ tăng; nhưng chương trình bị treo vì những lý do tôi không hiểu sau 30 giây - 1 phút. công việc.

So. Tôi nghĩ rằng cách tốt nhất là sử dụng ít ổ khóa hơn hoặc chỉ sử dụng nó ở những nơi cần thiết. Vì vậy, tôi có 2 câu hỏi:

  1. Khóa có cần thiết khi tôi viết cho các biến được truy cập công khai (C# lists) hoặc ngay cả khi tôi đọc chúng?

  2. Khóa có cần thiết chỉ trong các chủ đề không đồng bộ được tạo bởi trình xử lý ổ cắm hoặc ở những nơi khác không?

Ai đó có thể cung cấp cho tôi một số nguyên tắc thực tiễn, về cách vận hành. Tôi sẽ không đăng toàn bộ mã lần này. Nó không có ý nghĩa để đăng khoảng 2500 dòng mã.

+2

Không đủ cụ thể, nhìn vào đây để thông tin chung: http://www.albahari.com/threading/ – eulerfx

+1

Có toàn bộ phạm vi của chương trình có thể - từ hoàn toàn sai/tốc độ nhanh đến luôn luôn đúng/hợp lý chậm. Bạn dường như nhấn cả hai đầu trong các thử nghiệm của mình. An toàn luồng là chủ đề không tầm thường, vì vậy tôi khuyên bạn nên đọc nó thay vì chỉ cố gắng để có được "hướng dẫn thực tế". I E. Liên kết của eulerfx là điểm khởi đầu tốt. –

Trả lời

33

Khóa có cần thiết khi tôi viết cho các biến được truy cập công khai (chỉ có trong C#) hoặc ngay cả khi tôi đọc từ chúng?

Có (ngay cả khi bạn đọc).

Khóa có cần thiết chỉ trong các chủ đề không đồng bộ được tạo bởi trình xử lý ổ cắm hoặc ở những nơi khác không?

Có. Bất cứ nơi nào mã truy cập vào một phần của mã được chia sẻ, luôn luôn khóa.


này nghe có vẻ như bạn có thể không được khóa cá nhân đối tượng, nhưng khóa một điều cho tất cả các tình huống khóa.

Nếu vậy đưa vào thông minh rời rạc khóa bằng cách tạo ra đối tượng độc đáo cá nhân mà liên quan và khóa chỉ phần nhất định tại một thời điểm, mà không ảnh hưởng đến các chủ đề khác trong các phần khác.

Dưới đây là một ví dụ:

// This class simulates the use of two different thread safe resources and how to lock them 
// for thread safety but not block other threads getting different resources. 
public class SmartLocking 
{ 
    private string StrResource1 { get; set; } 
    private string StrResource2 { get; set; } 

    private object _Lock1 = new object(); 
    private object _Lock2 = new object(); 

    public void DoWorkOn1(string change) 
    { 
     lock (_Lock1) 
     { 
      _Resource1 = change; 
     } 
    } 

    public void DoWorkOn2(string change2) 
    { 
     lock (_Lock2) 
     { 
      _Resource2 = change2; 
     } 
    } 
} 
+3

Xin chào anh .. Anh đã cứu mạng tôi ..Tôi đã sử dụng các khóa khác nhau (với các đối tượng tĩnh khác nhau) cho các tình huống khác nhau và bây giờ ứng dụng hoạt động như một sự quyến rũ. Cảm ơn nhiều. –

+0

Tôi ngạc nhiên khi chủ đề này bị khóa! Không có ý định chơi chữ. Việc sử dụng ổ khóa không đúng cách có thể dẫn đến tình trạng đua của defacto mà nó xuất hiện với tôi. Tôi vui vì câu trả lời của tôi có thể giúp bạn. – OmegaMan

+10

@ClaudioFerraro: Điều đó tốt, nhưng bây giờ bạn có thể đang giao dịch một vấn đề (hiệu suất xấu) cho một số khác (deadlocks). Bạn có thể đi vào một tình huống mà thread 1 đã lấy ra khóa A và đang chờ khóa B, và thread 2 đã lấy ra khóa B và đang chờ khóa A, và do đó tất nhiên cả hai sẽ chờ đợi mãi mãi. Khi bạn thêm khóa chi tiết hơn vào chương trình của mình, bạn phải thiết lập giao thức đặt hàng nghiêm ngặt cho tất cả các khóa **. Bạn phải nói, ví dụ: "Tôi sẽ không bao giờ cho phép bất kỳ chủ đề nào yêu cầu khóa 1 * sau * đã có khóa 2". Vấn đề của bạn chỉ mới bắt đầu; điều này thật khó. –

0

Về cơ bản điều này có thể được trả lời khá đơn giản:

Bạn cần phải khóa tất cả những điều mà được truy cập bởi chủ đề khác nhau. Nó thực sự không quan trọng nếu nó về đọc hoặc viết. Nếu bạn đang đọc và một luồng khác ghi đè dữ liệu cùng một lúc thì dữ liệu đọc có thể không hợp lệ và bạn có thể đang thực hiện các hoạt động không hợp lệ.

2

Luôn sử dụng khóa khi bạn truy cập các thành viên (đọc hoặc ghi). Nếu bạn đang lặp qua bộ sưu tập và từ một chuỗi khác, bạn đang xóa các mục, mọi thứ có thể diễn ra nhanh chóng.

Đề xuất là khi bạn muốn lặp lại bộ sưu tập, sao chép tất cả các mục vào bộ sưu tập mới và sau đó lặp lại bản sao. I E.

var newcollection; // Initialize etc. 
lock(mycollection) 
{ 
    // Copy from mycollection to newcollection 
} 

foreach(var item in newcollection) 
{ 
    // Do stuff 
} 

Tương tự, chỉ sử dụng khóa thời điểm bạn thực sự đang ghi vào danh sách.

85

Bạn đã bao giờ ngồi trong xe hơi hoặc trên xe buýt với đèn đỏ khi không có giao thông chéo? Big lãng phí thời gian, phải không? Một khóa giống như một đèn giao thông hoàn hảo. Nó luôn luôn là màu xanh lá cây ngoại trừ khi có giao thông trong giao lộ.

Câu hỏi của bạn là "Tôi dành quá nhiều thời gian trong giao thông chờ đợi ở đèn đỏ. Tôi có nên chạy đèn đỏ hay không? Hoặc thậm chí tốt hơn, tôi nên tháo đèn hoàn toàn và chỉ để mọi người lái xe qua giao lộ ở tốc độ đường cao tốc bất kỳ điều khiển giao lộ nào? "

Nếu bạn gặp sự cố về hiệu suất với khóa thì hãy xóa khóa là điều cuối cùng bạn nên làm. Bạn đang đợi đèn đỏ chính xác vì có giao thông ngang tại giao lộ. Khóa là cực kỳ nhanh nếu chúng không bị ngăn cản.

Bạn không thể loại bỏ ánh sáng mà không loại bỏ lưu lượng truy cập chéo trước. Do đó, giải pháp tốt nhất là loại bỏ lưu lượng truy cập chéo. Nếu khóa là không bao giờ contended sau đó bạn sẽ không bao giờ chờ đợi ở đó. Tìm hiểu lý do tại sao lưu lượng giao thông vượt quá nhiều thời gian trong giao lộ; không loại bỏ ánh sáng và hy vọng không có va chạm. Sẽ có.

Nếu bạn không thể làm điều đó, sau đó, thêm thêm nhiều khóa mịn hơn đôi khi giúp. Đó là, có thể bạn có mọi con đường trong thị trấn hội tụ trên cùng một giao lộ. Có thể bạn có thể chia nó thành hai nút giao, để mã có thể di chuyển qua hai nút giao nhau khác nhau cùng một lúc.

Lưu ý rằng khiến những chiếc xe nhanh hơn (nhận được một bộ xử lý nhanh hơn) hoặc làm những con đường ngắn hơn (loại trừ đang con đường dài) thường làm cho vấn đề tồi tệ hơn trong các kịch bản đa luồng. Cũng giống như trong đời thực; nếu vấn đề là tắc nghẽn thì mua xe nhanh hơn và lái xe trên những con đường ngắn hơn sẽ khiến chúng bị kẹt xe nhanh hơn, nhưng không nhanh hơn.

+22

+1, tôi luôn thích những câu trả lời kiểu ẩn dụ này. Làm cho mọi việc trở nên dễ hiểu hơn nhiều. – jadarnel27

+1

Cảm ơn bạn đã trả lời. Nó khá rõ ràng câu trả lời của bạn nhưng ý định của tôi là hỏi: "nếu trong cuộc sống thực, mọi người đã phát minh ra các vòng tròn giao thông như thế nào tôi có thể xác định xem họ nên có hiệu suất tốt hơn bao nhiêu. Vì vậy, tôi chỉ mong đợi một câu trả lời cụ thể hơn. nên to hơn 100 lần so với chiếc nhẫn của vợ tôi "o một cái gì đó như thế! –

1

Lý do mà bạn cần phải khóa trong khi đọc là:

giả sử bạn đang làm thay đổi một thuộc tính và nó đã được đọc hai lần trong khi thread là Inbetween một khóa. Ngay trước khi chúng tôi thực hiện bất kỳ thay đổi nào và một thay đổi khác sau đó, chúng tôi sẽ có kết quả không phù hợp.

Tôi hy vọng rằng sẽ giúp,

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