2009-03-26 38 views
26

Trong chương trình .NET đa luồng, các tiêu chí quyết định cho việc sử dụng ThreadPool.QueueUserWorkItem so với bắt đầu luồng của riêng tôi thông qua Thread mới() và Thread.Start() là gì?Lợi thế của việc sử dụng Thread.Start vs QueueUserWorkItem

Trong ứng dụng máy chủ (ví dụ: ứng dụng ASP.NET hoặc dịch vụ WCF) tôi nghĩ ThreadPool luôn ở đó và sẵn có. Điều gì về trong một ứng dụng khách, như một ứng dụng WinForms hoặc WPF? Có một chi phí để quay lên hồ bơi thread? Nếu tôi chỉ muốn 3 hoặc 4 luồng để làm việc trong một thời gian ngắn trên một số tính toán, thì tốt hơn là QUWI hoặc vào Thread.Start().

Trả lời

21

ThreadPool luôn ở đó, tuy nhiên, có một số lượng hữu hạn các luồng được phân bổ cho nhóm dựa trên số lượng bộ xử lý. Đối với các ứng dụng ASP.NET, thường là một ý tưởng tồi khi sử dụng Threads trừ khi bạn thực sự bắt đầu một quá trình Async và biết rằng sẽ không có một số lượng lớn các yêu cầu (hãy nhớ rằng có một số lượng hữu hạn các luồng trong ThreadPool mà bạn chia sẻ với mọi thứ đang chạy trong AppDomain của bạn và có một giới hạn thực tế về tổng số chủ đề bạn muốn tạo bằng cách sử dụng Thread() mới).

Đối với các ứng dụng WinForms, hãy cân nhắc sử dụng BackgroundWorker thay vì sử dụng Thread hoặc ThreadPool. Nó sử dụng ThreadPool, tuy nhiên, nó làm cho giao tiếp giữa các chủ đề dễ dàng hơn trên các lập trình hiểu biết đa luồng.

Cập nhật

Tránh sử dụng ThreadPool.QueueUserWorkItem như hồ bơi ứng dụng của bạn có thể biến mất bất cứ lúc nào. Di chuyển công việc này ra ngoài hoặc sử dụng WebBackgrounder nếu bạn phải.

Từ Hanselman.com - "Checklist: What NOT to do in ASP.NET"

4

thảo luận này sẽ giúp bạn
When should I not use the ThreadPool in .Net?

+0

Tôi đã không thực sự hưởng lợi từ cuộc thảo luận đó, mà dường như chủ yếu là một cuộc tranh luận về chi phí bắt đầu một sợi. – Cheeso

+0

Tôi nghĩ rằng liên kết thật tuyệt vời. Tôi đã không thấy bất cứ điều gì về chi phí bắt đầu một sợi trong câu trả lời được chấp nhận - nhưng một số hạn chế của threadpool được liệt kê khá tốt ở đó. – BrainSlugs83

1

quan tâm Những hồ bơi thread phải lúc nào cũng có sẵn trong các ứng dụng .NET, bất kể những gì tốt bụng.

Chi phí để bắt đầu chuỗi từ nhóm chủ đề qua ThreadPool.QueueUserWorkItem sẽ không lớn hơn chi phí bắt đầu chuỗi của riêng bạn và có thể ít hơn.

Nếu bạn chỉ muốn một vài chủ đề trong một khoảng thời gian ngắn, hãy sử dụng nhóm chủ đề. Đó là những gì nó cho.

2

Nếu nhiệm vụ của bạn là ngắn nhiều khả năng bạn sẽ thấy hiệu suất tốt hơn nhiều bởi nhiệm vụ lịch trên hồ bơi thread qua QueueUserWorkItem hoặc BeginInvoke như bạn tránh được những chi phí lặp đi lặp lại của việc tạo ra và phá hủy đề của riêng bạn.

Hồ bơi chủ đề rõ ràng trả tiền cho việc tạo chủ đề, nhưng nó sử dụng lại các chủ đề, vì vậy bạn không phải trả chi phí cho mỗi công việc.

Bạn cũng có thể xem Threading in C# (ebook miễn phí).

0

Nếu bạn đang tạo chủ đề của riêng mình, bạn nên bắt đầu sử dụng lần đầu và sau đó để chúng trong một khoảng thời gian trong trường hợp bạn cần chúng một lần nữa - bạn thực hiện một chủ đề chờ đợi trên một sự kiện để bạn có thể kích hoạt lại nó bằng cách báo hiệu sự kiện, và sau một thời gian đủ dài trôi qua, luồng sẽ tự đánh thức và thoát ra, khai hoang các tài nguyên không được sử dụng.Bằng cách giữ một số lượng nhỏ các chủ đề nhàn rỗi sẵn sàng để được sử dụng lại, bạn giảm chi phí liên tục tạo và hủy các luồng (điều này có ý nghĩa đối với các hoạt động đủ ngắn ngủi).

Nhưng điều này về cơ bản là những gì hàng đợi chuỗi đã làm cho bạn - vì vậy bạn cũng có thể sử dụng nó. Đó là một vấn đề được giải quyết.

Một cuộc tranh luận tương tự được sử dụng để xảy ra trong cộng đồng C++ về chuỗi, tin hay không. Chúng ta có nên viết lớp chuỗi riêng của mình hay chúng ta nên sử dụng std::string? Câu trả lời tùy thuộc vào việc bạn muốn học cách viết một lớp chuỗi hay bạn đã làm xong điều đó và bạn muốn tiếp tục phát minh ra một điều gì đó mới mẻ.

+0

Đối với vấn đề bạn mô tả, sử dụng mô hình lập trình không đồng bộ là nhiều hơn nữa desireable, và nó sử dụng iirc ThreadPool - và không tiêu thụ tài nguyên bổ sung trong thời gian nhàn rỗi. –

14

Tôi sẽ đưa ra nhận xét này nhưng đã quá dài.
CodemonkeyKing dường như đã đạt được một điểm quan trọng, mặc dù không đủ mạnh theo ý kiến ​​của tôi.

Có rất nhiều tiêu chí bạn có thể sử dụng để mô tả mã. Nó sẽ được sử dụng trong một ứng dụng chạy dài hay không? Winforms ứng dụng hay không? Đây có phải là ứng dụng Máy chủ hoặc ứng dụng khách không? thư viện hoặc exe độc ​​lập? v.v.

Dường như với tôi rằng nếu mã của bạn sẽ chạy trong một ứng dụng độc lập và bạn có quyền kiểm soát tất cả mã xung quanh, thì bạn có thể cuộn hồ bơi chủ đề của riêng mình, bắt đầu chủ đề của riêng mình và đo lường và quản lý chi phí xung quanh khởi động luồng, độ trễ luồng và mức tiêu thụ tài nguyên. Hoặc bạn có thể sử dụng QUWI, nhưng nó sẽ không giết chết ứng dụng của bạn theo cách nào. Bạn được tự do lựa chọn. Mặt khác, nếu mã của bạn được đóng gói như một thư viện có thể được sử dụng trong một máy chủ -in ASP.NET, hoặc có thể trong một ứng dụng SQL CLR, hoặc một dịch vụ WCF - sau đó nó là một ý tưởng thực sự tồi tệ để tạo chủ đề. Bạn cần phải sử dụng QUWI hoặc một số cơ chế khác khai thác nhóm chủ đề tích hợp (như BackgroundWorker). Nếu nó được sử dụng trong các ứng dụng phía máy khách với các thư viện khác, một lần nữa, QUWI là bắt buộc. Hãy tưởng tượng rằng mọi thư viện muốn tận dụng lợi thế của các máy tính đa lõi đã cuộn các chuỗi của riêng chúng. Sẽ có sự hỗn loạn hoàn toàn trong các ứng dụng sử dụng nhiều thư viện. Chủ đề hung hăng, tất cả cạnh tranh cho cùng một tài nguyên. Không có sự phối hợp trung tâm của #threads vs # processor.

Tốt hygeine yêu cầu rằng thư viện, cho dù thư viện đó được sử dụng trong ứng dụng khách hay ứng dụng máy chủ, sử dụng luồng chung và điều đó có nghĩa là QUWI.

Điều cuối cùng để nhận ra là điều này;

Chuỗi được quản lý là chuỗi nền hoặc chuỗi tiền cảnh. Các chủ đề nền giống hệt với các chủ đề tiền cảnh với một ngoại lệ: một luồng nền không giữ cho môi trường thực thi được quản lý đang chạy. Một khi tất cả các chủ đề tiền cảnh đã được dừng lại trong một quá trình được quản lý (nơi tệp .exe là một assembly được quản lý), hệ thống sẽ dừng tất cả các luồng nền và tắt.

Chủ đề thuộc về nhóm chủ đề được quản lý (có nghĩa là các chuỗi có thuộc tính IsThreadPoolThread là đúng) là các chuỗi nền. Tất cả các chuỗi nhập vào môi trường thực thi được quản lý từ mã không được quản lý đều được đánh dấu làm chủ đề nền. Tất cả các chủ đề được tạo ra bằng cách tạo và bắt đầu một đối tượng Thread mới là theo các chủ đề tiền cảnh mặc định.

Nếu bạn sử dụng một chuỗi để theo dõi hoạt động, chẳng hạn như kết nối ổ cắm, hãy đặt thuộc tính IsBackground thành true để chủ đề không ngăn quá trình chấm dứt của bạn.

từ MSDN site.

2

Đây là một lợi thế khác khi sử dụng ThreadPool.QueueUserWorkItem.

Tôi có ứng dụng winforms có âm thanh sôi nổi. Ban đầu, tôi đã triển khai điều này bằng cách sử dụng

  heartbeat = new Thread(HeartbeatDoWork); 
     heartbeat.Start(); 

Hoạt động tốt 98% thời gian. Tuy nhiên khi ứng dụng được đóng đôi khi nó không 'chết' đúng cách, tức là quá trình này vẫn hiển thị trong trình quản lý tác vụ.

Tóm lại, nhịp tim đã xuất bản một sự kiện và nó đã xử lý sự kiện (quán rượu/phụ CAB) nơi nó bị 'kẹt'.

Việc sửa chữa được dễ dàng, chỉ cần thay đổi để sử dụng này

  ThreadPool.QueueUserWorkItem(HeartbeatDoWork); 

tôi chắc chắn rằng có một vài điều thêm tôi có thể làm gì khi quay ra chủ đề của riêng tôi và nó sẽ được làm sạch đúng cách, nhưng điều này đơn giản hơn, nhanh hơn và dễ hiểu hơn ... ThreadPool thực hiện tất cả công việc cho tôi.

+9

có lẽ bạn nên thêm dòng: heartbeat.IsBackground = true; –

0

Một lợi thế của việc sử dụng Thread.Start() là, bạn có thể cố ý hủy bỏ chuỗi sau. Trong các ThreadPool bạn không có phương tiện kiểm soát việc thực hiện thread sau khi bạn enqueued nó.

+0

Đó là sự hiểu biết của tôi rằng nói chung bằng cách sử dụng Thread.Abort là một ý tưởng tồi vì nó có thể rò rỉ tài nguyên mà sau đó có thể không bao giờ có thể được làm sạch. Thời gian duy nhất nó nên được sử dụng là khi ứng dụng buộc phải tự tắt, do một số trạng thái lỗi không thể khôi phục. – devios1

+0

Có thể hủy bỏ một số thao tác 'ThreadPool'. Xem [this] (http://stackoverflow.com/questions/7731610/cancel-threadpool-queueuserworkitem-task). –

0

Hầu hết đọc của tôi đồng ý với Marcel, khả năng kiểm soát chuỗi nếu có điều gì đó (Abort ...) là điều cần được xem xét đặc biệt nếu bạn đang xử lý cuộc gọi của bên thứ ba mà bạn không kiểm soát và có thể treo.

+0

Giống như một bình luận! – Nitesh

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