Các câu trả lời khác ở đây dường như đang bỏ sót điểm quan trọng nhất:
Trừ khi bạn đang cố gắng song song một hoạt động đòi hỏi nhiều CPU để hoàn thành nó nhanh hơn trên một trang web tải thấp, nếu không thì chẳng ích gì khi sử dụng một chuỗi công nhân cả.
Điều đó áp dụng cho cả các luồng miễn phí, được tạo bởi new Thread(...)
và các luồng công nhân trong ThreadPool
phản hồi QueueUserWorkItem
các yêu cầu.
Vâng, đó là sự thật, bạn có thể chết đói ThreadPool
trong một quy trình ASP.NET bằng cách xếp hàng quá nhiều mục công việc. Nó sẽ ngăn ASP.NET xử lý các yêu cầu khác. Thông tin trong bài báo là chính xác về mặt đó; cùng một nhóm chủ đề được sử dụng cho QueueUserWorkItem
cũng được sử dụng để phục vụ các yêu cầu.
Nhưng nếu bạn thực sự đang xếp hàng đủ các hạng mục công việc để gây ra nạn đói này, thì bạn sẽ chết đói nhóm chủ đề! Nếu bạn đang chạy thực sự hàng trăm hoạt động đòi hỏi nhiều CPU cùng một lúc, thì sẽ tốt gì nếu có một luồng công nhân khác để phục vụ một yêu cầu ASP.NET, khi máy đã quá tải? Nếu gặp trường hợp này, bạn cần thiết kế lại toàn bộ!
Hầu hết thời gian tôi thấy hoặc nghe nói về mã đa luồng được sử dụng không phù hợp trong ASP.NET, nó không phải để xếp hàng đợi công việc đòi hỏi nhiều CPU. Nó dành cho công việc ràng buộc I / O xếp hàng. Và nếu bạn muốn làm I / O hoạt động, thì bạn nên sử dụng luồng I / O (I / O Completion Port).
Cụ thể, bạn nên sử dụng các lệnh gọi lại không đồng bộ được hỗ trợ bởi bất kỳ lớp thư viện nào bạn đang sử dụng. Các phương pháp này luôn được dán nhãn rất rõ ràng; chúng bắt đầu bằng các từ Begin
và End
. Như trong Stream.BeginRead
, Socket.BeginConnect
, WebRequest.BeginGetResponse
, và vân vân.
Các phương pháp này sử dụng ThreadPool
, nhưng chúng sử dụng IOCP, không can thiệp vào các yêu cầu ASP.NET. Chúng là một loại luồng nhẹ đặc biệt có thể được "đánh thức" bởi một tín hiệu ngắt từ hệ thống I / O. Và trong ứng dụng ASP.NET, bạn thường có một luồng I / O cho mỗi luồng công nhân, vì vậy mỗi yêu cầu đơn lẻ có thể có một hoạt động không đồng bộ được xếp hàng đợi. Đó thực sự là hàng trăm hoạt động không đồng bộ mà không có bất kỳ sự suy giảm hiệu suất đáng kể nào (giả sử hệ thống con I / O có thể theo kịp). Đó là cách nhiều hơn những gì bạn cần.
Chỉ cần lưu ý rằng ủy quyền không đồng bộ không hoạt động theo cách này - họ sẽ kết thúc bằng cách sử dụng một chuỗi công nhân, giống như vậy ThreadPool.QueueUserWorkItem
. Chỉ có các phương thức không đồng bộ được tích hợp sẵn của các lớp thư viện .NET Framework có khả năng thực hiện điều này. Bạn có thể tự làm, nhưng nó phức tạp và hơi nguy hiểm và có thể nằm ngoài phạm vi của cuộc thảo luận này.
Câu trả lời tốt nhất cho câu hỏi này, theo ý kiến của tôi, là không sử dụng ThreadPool
hoặc một phiên bản nền Thread
trong ASP.NET . Nó hoàn toàn không giống như xoay một chuỗi trong ứng dụng Windows Forms, nơi bạn làm điều đó để giữ cho giao diện người dùng luôn phản hồi và không quan tâm đến hiệu quả của nó. Trong ASP.NET, mối quan tâm của bạn là thông lượng và tất cả ngữ cảnh chuyển đổi trên tất cả các luồng công nhân đó sẽ hoàn toàn giết chết thông lượng của bạn cho dù bạn có sử dụng ThreadPool
hay không.
Xin vui lòng, nếu bạn thấy mình đang viết mã luồng trong ASP.NET - hãy xem xét liệu nó có thể được viết lại để sử dụng các phương thức không đồng bộ có sẵn từ trước hay không và nếu không thể, thì hãy xem xét liệu bạn có thực sự cần mã hay không để chạy trong một chuỗi nền. Trong hầu hết các trường hợp, bạn có thể sẽ thêm phức tạp mà không có lợi ích ròng.