Tạo chủ đề - Task.Factory.StartNew so với luồng mới ()


102

Tôi chỉ đang tìm hiểu về các thư viện Threading và Parallel mới trong .Net 4

Trước đây, tôi sẽ tạo một Chủ đề mới như vậy (làm ví dụ):

DataInThread = new Thread(new ThreadStart(ThreadProcedure));
DataInThread.IsBackground = true;
DataInThread.Start();

Bây giờ tôi có thể làm:

Task t = Task.Factory.StartNew(() =>
{
   ThreadProcedure();
});

Sự khác biệt nếu có là gì?

Cảm ơn


1
Bạn sẽ cần phải băn khoăn một chút về cách hoạt động của bộ lập lịch nhóm luồng. Nó có thể tạo ra sự khác biệt lớn nhưng tất cả phụ thuộc vào những gì bạn thực sự làm bên trong luồng.
Hans Passant

Câu trả lời:


79

Có một sự khác biệt lớn. Các tác vụ được lên lịch trên ThreadPool và thậm chí có thể được thực thi đồng bộ nếu hết hạn.

Nếu bạn có một công việc nền đang chạy lâu dài, bạn nên chỉ định điều này bằng cách sử dụng Tùy chọn Tác vụ chính xác.

Bạn nên thích Thư viện song song tác vụ hơn xử lý luồng rõ ràng, vì nó được tối ưu hóa hơn. Ngoài ra bạn có thêm các tính năng như Tiếp tục.


5
Không, không. Nó chỉ bắt đầu nhiệm vụ. Điều này có thể xếp hàng đợi nhiệm vụ tại nhóm luồng hoặc thực thi nó một cách đồng bộ. Các TPL là về giải phóng bạn khỏi việc quản lý các chủ đề / đồng thời bản thân và sử dụng tốt nhất cho nền tảng của bạn (như lõi sử dụng)
sanosdole

10
Có tùy chọn TaskCreationOptions.LongRunning sẽ luôn tạo một luồng khác, nhưng toàn bộ vấn đề là tại sao bạn cần một luồng khác? Nếu bạn chỉ muốn làm một việc gì đó song song (Main thực hiện trong khi Task chạy), bạn nên để một thư viện được tối ưu hóa quyết định cách sử dụng tài nguyên hệ thống như luồng để thực hiện việc này theo cách hiệu quả nhất.
sanosdole

3
Bài viết trên msdn này mô tả cách các tác vụ được lên lịch. Nó bao gồm kéo dài và nội tuyến (thực thi đồng bộ). msdn.microsoft.com/en-us/library/dd997402.aspx
sanosdole

2
@sming Vấn đề là bạn muốn xử lý đồng thời (không chặn giao diện người dùng) chứ không phải bạn muốn một chuỗi mới. ThreadPool sẽ không chặn luồng giao diện người dùng, nhưng quản lý các luồng nền hiệu quả hơn nhiều so với việc bạn có thể làm thủ công bằng cách tạo luồng. Đó là sự thay đổi trong quá trình tư duy mà TPL giới thiệu. Đừng nghĩ đến chủ đề, hãy nghĩ những nhiệm vụ đồng thời.
sanosdole

4
@sming Xin lỗi, câu đó hơi thô. Thực thi đồng bộ các tác vụ được gọi là nội tuyến. Khi lên lịch một tác vụ trên threadpool (bộ lập lịch mặc định) từ Chủ đề giao diện người dùng, nó sẽ không xảy ra. Nó sẽ chỉ xảy ra nếu bộ lập lịch môi trường xung quanh ('TaskScheduler.Current') giống với bộ lập lịch của tác vụ bạn gọi là '.Wait ()'. Vì '.Wait ()' đang chặn, nó vẫn sẽ chặn giao diện người dùng. Ngắn gọn: Không chờ cuộc gọi và nó sẽ không được thực thi đồng bộ.
sanosdole

73

Nhiệm vụ cung cấp cho bạn tất cả tính tốt của API tác vụ:

  • Thêm liên tục ( Task.ContinueWith)
  • Chờ nhiều nhiệm vụ hoàn thành (tất cả hoặc bất kỳ)
  • Ghi lại các lỗi trong nhiệm vụ và thẩm vấn chúng sau đó
  • Ghi lại quá trình hủy (và cho phép bạn chỉ định việc hủy bắt đầu)
  • Có thể có giá trị trả lại
  • Sử dụng await trong C # 5
  • Kiểm soát tốt hơn việc lập lịch (nếu nó sẽ hoạt động lâu dài, hãy nói như vậy khi bạn tạo tác vụ để bộ lập lịch tác vụ có thể tính đến điều đó)

Lưu ý rằng trong cả hai trường hợp, bạn có thể làm cho mã của mình đơn giản hơn một chút với chuyển đổi nhóm phương pháp:

DataInThread = new Thread(ThreadProcedure);
// Or...
Task t = Task.Factory.StartNew(ThreadProcedure);

8
+1. Tôi muốn nói thêm rằng đó Threadlà mức độ rất thấp so với Task(Tôi có một bài đăng trên blog nói chi tiết). Tôi đang nói chuyện "sử dụng Công việc trong thế giới thực" tại Grand Rapids DevDay . Cuộc nói chuyện được gọi là "Chủ đề đã chết", vì không còn cần thiết nữa Thread(trừ khi bạn đang triển khai a TaskScheduler).
Stephen Cleary

@StephenCleary, tôi cho rằng ý bạn Threadlà đã chết, khi nó được sử dụng làm luồng nền?
ebb

1
@ebb: Không, tôi có quan điểm mạnh mẽ hơn được mô tả trong nhận xét đầu tiên của tôi. Không có gì Threadcó thể làm (hoặc BackgroundWorker) không thể được thực hiện một cách thanh lịch hơn với Taskvà một sự thích hợp TaskScheduler.
Stephen Cleary

1
@StephenCleary, Bạn sẽ tạo một chuỗi chuyên dụng mà không cần sử dụng Threadnhư thế nào?
ebb

4
@ebb: Tôi không rõ "Chủ đề chuyên dụng". Nếu bạn muốn có một Taskđể chạy trên một sợi đặc biệt, sau đó sử dụng một cách phù hợp TaskScheduler- ví dụ như, AsyncContextThread. Tuy nhiên, điều này thường không cần thiết; các SynchronizationContext, ThreadPoolConcurrentExclusiveSchedulerPairschedulers là đủ cho hầu hết các chương trình này.
Stephen Cleary

12

Trong trường hợp đầu tiên, bạn chỉ đơn giản là bắt đầu một luồng mới trong khi trong trường hợp thứ hai, bạn đang nhập nhóm luồng.

Công việc của nhóm luồng là chia sẻ và tái chế các luồng. Nó cho phép tránh mất vài mili giây mỗi khi chúng ta cần tạo một luồng mới.

Có một số cách để vào nhóm chủ đề:

  • với TPL (Task Parallel Library) như bạn đã làm
  • bằng cách gọi ThreadPool.QueueUserWorkItem
  • bằng cách gọi BeginInvoke trên một đại biểu
  • khi bạn sử dụng BackgroundWorker

1

Khối mã đầu tiên của bạn yêu cầu CLR tạo một Luồng (giả sử. T) cho bạn. Luồng này có thể được chạy dưới dạng nền (sử dụng các luồng nhóm luồng khi lập lịch T). Nói một cách ngắn gọn, bạn yêu cầu CLR tạo một luồng để bạn thực hiện một việc gì đó và gọi phương thức Start () trên luồng để bắt đầu.

Khối mã thứ hai của bạn cũng làm như vậy nhưng ủy quyền (chuyển giao ngầm) trách nhiệm tạo luồng (background- chạy lại trong nhóm luồng) và luồng bắt đầu thông qua phương thức StartNew trong việc triển khai Task Factory.

Đây là sự khác biệt nhanh chóng giữa các khối mã nhất định. Phải nói rằng, có rất ít sự khác biệt chi tiết mà bạn có thể google hoặc xem các câu trả lời khác từ các cộng tác viên của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.