2009-03-16 83 views
6

Tôi đã gặp phải tình trạng khó xử khá khó xử trong một dự án tại nơi làm việc. Chúng ta cần tạo người dùng trên 4 hoặc 5 dịch vụ khác nhau và đã thiết lập nó theo cách mà nếu không thành công, tất cả đều thất bại. Chúng được đóng gói trong một khối phạm vi giao dịch.Đồng bộ hóa cuộc gọi không đồng bộ trong C#

Một trong những dịch vụ chúng tôi cần thêm người dùng để yêu cầu telnetting in và fudging một số dữ liệu. Có nhiều cách khác để làm điều đó (mà chi phí tiền bạc) nhưng bây giờ đó là những gì chúng tôi đang mắc kẹt với. Việc thêm một người dùng mất khoảng 3 phút. Chúng tôi sẽ làm việc để làm cho nó xuống đáng kể như có thể tưởng tượng nhưng đó không thực sự là điểm. Cuộc gọi này không đồng bộ và loại phải hoạt động chính xác. Cú đấm là, chỉ có thể có tối đa 10 kết nối với dịch vụ.

Dự án của chúng tôi đang được thiết lập để tạo người dùng theo lô. Vì vậy, có khả năng 50 người dùng được tạo ra tại một thời điểm. Điều này cho thấy một vấn đề khi chỉ có 10 kết nối có thể được thực hiện thông qua telnet, và một người dùng đã qua xử lý không thể mất nhiều thời gian hơn dịch vụ telnet. Bây giờ tôi cần phải đồng bộ hóa quá trình này để phần còn lại không thể tiếp tục cho đến khi nó kết thúc.

Chúng tôi đang sử dụng cuộc gọi lại và đại biểu có cuộc gọi không đồng bộ để triển khai chức năng. Điều gì sẽ là cách tốt nhất để đóng gói phần không đồng bộ, và không tiếp tục cho đến khi nó được hoàn thành?

Chúng tôi có nên thiết lập vòng lặp chỉ chấm dứt khi cuộc gọi kết thúc? Có một cái gì đó trong thư viện Threading có thể giúp đỡ? Tôi đã không bao giờ làm việc với các chủ đề trước đây vì vậy đây sẽ là một đầu tiên cho tôi. Có những công cụ nào để giúp giải quyết vấn đề này?

EDIT:

Nếu tôi sử dụng BeginInvoke/EndInvoke mẫu, sẽ asynch cuộc gọi trong phạm vi các đại biểu đầu tiên tôn vinh bắt đầu/kết thúc cũng?

Ví dụ:

public void dele1(string message) { 
    Console.Write(message); 
    delegate2 del2 = new delegate2; 
    del2(); 
    Console.Write("End of Delegate 2"); 
} 

public void dele2() { 
    // Long Processing 
    Console.Write("Delegate 2"); 
} 

public delegate void delegate1(String message); 
public delegate void delegate2(); 

delegate1 del1 = new delegate1(dele1); 
del1("Delegate 1").BeginInvoke; 
del1().EndInvoke; 
Console.Write("End of Delegate 1"); 

// Dự kiến ​​Output (End Invoke chờ đợi cho đến khi Đại biểu 2 được hoàn thành):

Delegate 1 
End of Delegate 2 
Delegate 2 
End of Delegate 1 

// Hoặc (End Invoke chỉ chờ đại biểu 1 để kết thúc nhưng không bất kỳ cuộc gọi đại biểu nội bộ nào):

Delegate 1 
End of Delegate 2 
End of Delegate 1 
Delegate 2 

Sẽ kết thúc yêu cầu chờ cho đến khi đại biểu thứ hai xử lý xong als o? Hoặc tôi sẽ cần phải sử dụng các mẫu gọi trên tất cả các cuộc gọi đại biểu?

+0

Không chắc chắn về cú pháp của bạn cho ví dụ đã chỉnh sửa của bạn. Bạn có thể làm rõ thêm những gì đang xảy ra với del1? – strager

Trả lời

7

Bạn thực sự có thể sử dụng màn hình, semaphores hoặc thậm chí bạn có thể quay đợi cho đến khi (các) cuộc gọi phương thức không đồng bộ được thực hiện.

Nhưng bạn cũng có thể sử dụng tiện ích này miễn phí. Nếu bạn gọi EndInvoke() trên một đại biểu đã được bắt đầu trước đó với BeginInvoke(), bạn sẽ chặn cho đến khi hoàn thành công việc không đồng bộ.

Không chắc chắn điều này có hữu ích không vì bạn phải sử dụng mẫu không đồng bộ này. Nếu có, bạn sẽ nhận được thực thi Không đồng bộ (và chuyển đổi từ Không đồng bộ trở lại các cuộc gọi đồng bộ) miễn phí.

Khám phá Calling Synchronous Methods Asynchronously on MSDN để biết thêm thông tin về mẫu này.

Tôi hy vọng điều này sẽ hữu ích!

+0

Điều đó nghe giống như chính xác những gì tôi cần! Cảm ơn bạn đời. –

2

Nghe có vẻ như tôi muốn bạn xếp hàng ... nếu có yêu cầu đang diễn ra, hãy thêm vào hàng đợi (với số Monitor); khi cuộc gọi hoàn tất, hãy kiểm tra hàng đợi ...

0

Bạn có một vài tùy chọn. Dưới đây là một vài ý tưởng -

Trước hết, bạn có thể sử dụng ManualResetEvent để "chặn" chuỗi chính cho đến khi các thao tác không đồng bộ của bạn hoàn tất. Ý tưởng là chỉ có chủ đề chính gọi hàm bạn, sau đó thực hiện event.WaitOne() và hàm chịu trách nhiệm thiết lập sự kiện.

Ngoài ra, bạn có thể thử sử dụng một cái gì đó như Semaphore. Nó được thiết kế để giúp đỡ trong những tình huống này, vì bạn có thể giới hạn nó đến 10 lần xuất hiện đồng thời mà không phải lo lắng về việc cố tự xử lý nó. Đây có lẽ là cách tiếp cận ưa thích của tôi.

0

Có hai lý do cho việc sử dụng đề:

  • để tận dụng tài nguyên CPU, vì vậy đẩy mạnh việc lên
  • để viết một số máy nhà nước đồng thời các phương pháp như đơn giản, mà làm cho chúng dễ đọc hơn

Những bất lợi của việc sử dụng chủ đề là:

  • nó reall y khó khăn

Nếu nút cổ chai chờ 3 phút trên máy từ xa, có thể cần lưu ý rằng nhiều chuỗi sẽ không giúp bạn có được lợi thế về hiệu suất. Bạn có thể viết toàn bộ thiing đơn luồng, duy trì một bộ lên đến mười "máy nhà nước" đối tượng và di chuyển chúng thông qua các giai đoạn tạo người dùng, tất cả từ một chủ đề, với sự khác biệt nhỏ trong hơn tất cả hiệu suất.

Vì vậy, những gì bạn có thể tìm kiếm là bố cục mã dễ đọc, bằng cách làm cho thao tác tạo người dùng thành chuỗi các cuộc gọi đọc giống như một phương thức duy nhất (chúng sẽ là nếu bạn chạy chúng làm chuỗi).

Một cách khác để thực hiện điều đó là thông qua phương pháp trình lặp, tức là chứa các câu lệnh yield return, cũng cung cấp cho bạn những lợi thế về khả năng đọc đơn phương pháp. Tôi phải có linked to this three times trong tuần trước! Đó là bài viết của Jeffrey Richter về AsyncEnumerator.

2

IAsyncResult có thuộc tính AsyncWaitHandle cung cấp cho bạn xử lý chờ (nếu có) sẽ được báo hiệu khi thao tác hoàn tất.

Vì vậy, bạn có thể sử dụng WaitHandle.WaitAll (hoặc .WaitAny) để thực hiện việc chờ không quay trên nhiều tay cầm cùng một lúc.

0

Tôi không rõ ràng về cách bạn đang sử dụng TransactionScope (vì vậy tôi có thể tắt cơ sở), nhưng bạn có thể tạo DependentTransactions có thể được chia nhỏ cho chuỗi công việc. Giao dịch cấp cao nhất của bạn sẽ không cam kết cho đến khi tất cả các DependentTransactions cam kết thành công và ngược lại với rollback. Tôi đã tìm thấy điều này như là một cách dễ dàng để làm tất cả hoặc không có gì trên các chủ đề miễn là các hoạt động bạn đang gọi gói gọn chức năng cam kết/rollback (IEnlistmentNotification hoặc tương tự).

+0

Bạn nói đúng, và nếu chúng tôi không giới hạn trong 10 kết nối tối đa cho quá trình cuối cùng, điều này sẽ ổn. Thật không may, chúng tôi được giới hạn trong 10 (thực sự chúng tôi được phép 2), vì vậy nó dễ dàng hơn để làm tất cả trong chuỗi thay vì giữ một hàng đợi. –

+0

Kết nối đồng thời bị giới hạn ... luôn là yêu cầu thú vị;) – jsw

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