2010-03-30 17 views
23

Chúng tôi có một dịch vụ WCF làm cho rất nhiều các cuộc gọi NHibernate giao dịch. Thỉnh thoảng, chúng tôi đã thấy thời gian chờ SQL, mặc dù các cuộc gọi đang cập nhật các hàng khác nhau và các bảng được đặt thành khóa cấp hàng.Các sự cố đồng thời có thể xảy ra khi sử dụng thuộc tính Hành vi dịch vụ WCF được đặt thành ConcurrencyMode.Multiple và InstanceContextMode.PerCall không?

Sau khi đào sâu vào nhật ký, có vẻ như các luồng khác nhau đã nhập cùng một điểm trong mã (giao dịch của chúng tôi bằng khối) và bản cập nhật đã bị treo trên cam kết. Nó không có ý nghĩa, tuy nhiên, bởi vì chúng tôi tin rằng các thuộc tính lớp dịch vụ sau được buộc một sợi thực hiện độc đáo cho mỗi cuộc gọi dịch vụ:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)] 

Chúng tôi gần đây đã thay đổi chế độ đồng thời để ConcurrencyMode.Single và chưa chạy vào bất kỳ vấn đề nào, nhưng lỗi rất khó để tái sản xuất (nếu có ai có bất kỳ suy nghĩ nào về việc xóa bỏ một lỗi như vậy, hãy cho tôi biết!).

Dù sao, tất cả đều đưa tôi đến câu hỏi của tôi: không phải một InstanceContextMode của PerCall thực thi thread-safety trong dịch vụ, ngay cả khi ConcurrencyMode được đặt thành nhiều? Làm thế nào có thể cho hai cuộc gọi được phục vụ bởi cùng một cá thể dịch vụ?

Cảm ơn!

Trả lời

24

Cách duy nhất để có hai máy khách WCF khác nhau, tức là, proxy, tham chiếu cùng một phiên bản dịch vụ WCF của bạn là sử dụng InstanceContextMode=InstanceContextMode.Single. Đây là một lựa chọn không tốt nếu mở rộng quy mô là một vấn đề, vì vậy bạn muốn sử dụng PerCall nếu có thể.

Khi bạn sử dụng PerCall, mỗi CALL đến các dịch vụ WCF được phục vụ riêng dụ WCF nó. Không có sự chia sẻ của cá thể dịch vụ, nhưng điều đó không có nghĩa là chúng không chia sẻ cùng một lưu trữ back-end (ví dụ: cơ sở dữ liệu, bộ nhớ, tệp, v.v.). Chỉ cần nhớ, PerCall cho phép mỗi gọi để truy cập dịch vụ WCF của bạn cùng một lúc.

Cài đặt ConcurrencyMode kiểm soát mô hình luồng của chính dịch vụ. Cài đặt Single hạn chế tất cả các phiên bản dịch vụ WCF để chạy trên cùng một chuỗi. Vì vậy, nếu bạn có nhiều khách hàng kết nối cùng một lúc, họ sẽ chỉ được thực hiện một lần tại một bên dịch vụ WCF. Trong trường hợp này, bạn sử dụng WCF để cung cấp đồng bộ hóa. Nó sẽ hoạt động tốt, như bạn đã thấy, nhưng hãy nghĩ về điều này khi chỉ có điều khiển mức vĩ mô trên đồng bộ hóa - mỗi cuộc gọi dịch vụ WCF sẽ thực hiện toàn bộ trước khi cuộc gọi tiếp theo có thể thực thi.

Đặt ConcurrencyMode thành Multiple, tuy nhiên, sẽ cho phép tất cả các phiên bản dịch vụ WCF thực thi đồng thời. Trong trường hợp này, bạn chịu trách nhiệm cung cấp đồng bộ hóa cần thiết. Hãy nghĩ về điều này là có điều khiển mức vi mô trên đồng bộ hóa vì bạn chỉ có thể đồng bộ hóa các phần của mỗi cuộc gọi cần được đồng bộ hóa.

Tôi hy vọng tôi đã giải thích này cũng đủ, nhưng đây là một đoạn trong tài liệu MSDN cho ConcurrencyMode chỉ trong trường hợp:

Setting ConcurrencyMode để đơn lệnh cho hệ thống để hạn chế thể hiện của các dịch vụ cho một thread thực hiện tại một thời điểm, giải phóng bạn xử lý các vấn đề về luồng . Giá trị Đa có nghĩa là các đối tượng dịch vụ có thể được thực hiện bởi nhiều chủ đề cùng một lúc. Trong trường hợp này, bạn phải đảm bảo an toàn cho chủ đề .

EDIT

Bạn hỏi

Có bất kỳ sự gia tăng hiệu suất, sau đó, sử dụng PerCall vs Độc thân khi sử dụng ConcurrencyMode.Single? Hay là ngược lại đúng?

Điều này có thể phụ thuộc vào dịch vụ.

Với InstanceContextMode.PerCall, một cá thể dịch vụ mới được tạo cho mỗi và mọi cuộc gọi qua proxy, do đó bạn có phí tạo đối tượng để xử lý. Giả sử nhà xây dựng dịch vụ của bạn không làm được gì nhiều, điều này sẽ không thành vấn đề.

Với InstanceContextMode.Single, chỉ một phiên bản dịch vụ tồn tại trong suốt thời gian tồn tại của ứng dụng, vì vậy thực tế không có phí liên quan đến việc tạo cá thể. Tuy nhiên, chế độ này chỉ cho phép một cá thể dịch vụ xử lý mọi cuộc gọi sẽ được thực hiện. Vì vậy, nếu bạn có nhiều cuộc gọi được thực hiện đồng thời, mỗi cuộc gọi sẽ phải đợi cho các cuộc gọi khác kết thúc trước khi nó có thể được thực thi.

Đối với những gì đáng giá, dưới đây là cách tôi đã thực hiện việc này. Sử dụng ngữ cảnh ngữ cảnh PerCall với Multiple đồng thời. Bên trong lớp dịch vụ WCF của bạn, tạo các thành viên tĩnh để quản lý lưu trữ dữ liệu phía sau cho bạn, và sau đó đồng bộ hóa quyền truy cập vào các thành viên tĩnh này khi cần sử dụng câu lệnh lock, volatile, v.v. an toàn chủ đề.

+0

Bạn chắc chắn đóng đinh sự ngắt kết nối khác của tôi. Vì vậy, sử dụng 'ConcurrencyMode.Multiple', bất kể InstanceContextMode, có nghĩa là bạn đang sử dụng các câu lệnh' lock' xung quanh các phần quan trọng và thực hiện các kiểm tra đồng bộ/an toàn luồng khác. Có tăng hiệu năng nào không, sau đó, sử dụng 'PerCall' và' Single' khi sử dụng 'ConcurrencyMode.Single'? Hay là ngược lại đúng? –

+0

http://msdn.microsoft.com/en-us/library/ms731193.aspx –

+0

Đây là tất cả thông tin tuyệt vời. Cảm ơn vì đã quá thấu đáo; Tôi nhận được rất nhiều từ nó. –

7

Tôi tin rằng câu trả lời là thực tế là có nhiều luồng (ở phía máy khách) sử dụng cùng một cá thể proxy, do đó có khả năng cho phép nhiều cuộc gọi vào cùng một cá thể. Điều này post có một lời giải thích chi tiết hơn.

+0

Đó là một bài viết tuyệt vời và tôi nghĩ rằng thực sự làm sáng tỏ vấn đề (chúng tôi lưu trữ proxy ở cấp miền ứng dụng ở phía máy khách, mà nhiều yêu cầu web sử dụng). Vì vậy, là các tùy chọn 1) Để làm cho các hoạt động dịch vụ thread-an toàn và mở cho mỗi cuộc gọi lên đến nhiều chủ đề hoặc 2) chỉ cần để nó như là duy nhất và có hiệu suất hit? Chỉ muốn chắc chắn rằng tôi không thiếu gì đó! –

+0

Hoặc tôi đoán có khả năng một tùy chọn 3 sẽ là tạo proxy mới cho mọi yêu cầu ...? –

+0

@Brandon Linton, sử dụng proxy mới cho mỗi yêu cầu sẽ không giải quyết được sự cố nếu bạn sử dụng ngữ cảnh ngữ cảnh 'PerCall' và chế độ đồng thời' Nhiều'. Trong trường hợp này, bạn ** phải ** tự cung cấp an toàn cho dù bạn có tạo proxy mỗi lần hoặc sử dụng lại cùng một lần hay không. –

2

InstanceContextMode.PerCallConcurrencyMode.Single sẽ ổn nếu bạn không sử dụng hai cách gọi lại trên máy chủ. Trong trường hợp đó, bạn sẽ cần phải sử dụng ConcurrencyMode.Reentrant hoặc gọi lại sẽ không thể truy cập vào bản ghi dịch vụ bị khóa và một bế tắc sẽ xảy ra.

Kể từ khi tạo một cá thể dịch vụ cho mỗi cuộc gọi, không thể cho các chủ đề hoặc cuộc gọi khác truy cập vào nó. Như đã nêu trong bài viết được đề cập trong các câu trả lời khác article kết hợp như vậy vẫn có thể là một vấn đề nếu phiên là creatd ở cấp ràng buộc VÀ bạn đang sử dụng cùng một đối tượng proxy dịch vụ. Vì vậy, nếu bạn không sử dụng cùng một đối tượng proxy hoặc không có một ràng buộc sessionful và không sử dụng hai cách gọi lại cho khách hàng (rất có thể họ nên được OneWay anyway) InstanceContextMode.PerCallConcurrencyMode.Single nên được tốt.

1

Tôi nghĩ tất cả điều đó phụ thuộc vào yêu cầu. Nếu chúng ta gọi cùng một dịch vụ nhiều lần thì tốt hơn chúng ta có thể sử dụng InstanceContextMode là Single và concurrencymode là nhiều.

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