2010-08-11 52 views
22

Tôi hiện đang thay thế một số nhà nướng chức năng nhiệm vụ với một thực hiện mới sử dụng các chức năng System.Threading.Tasks mới được tìm thấy trong .net 4.Làm thế nào để nhận được thông báo rằng một System.Threading.Tasks.Task đã hoàn

Tôi có một vấn đề nhỏ mặc dù, và mặc dù tôi có thể nghĩ ra một số giải pháp tôi muốn một số lời khuyên mà trên đó thường là cách tốt nhất để làm điều đó, và nếu tôi thiếu một thủ thuật ở đâu đó.

Điều tôi cần là cho một quá trình tùy ý để có thể bắt đầu Tác vụ nhưng sau đó tiếp tục và không đợi Công việc kết thúc. Không phải là một vấn đề, nhưng khi tôi sau đó cần phải làm một cái gì đó với kết quả của một nhiệm vụ tôi không khá chắc chắn cách tốt nhất để làm điều đó.

Tất cả các ví dụ tôi đã thấy sử dụng Wait() trên tác vụ cho đến khi nó hoàn thành hoặc tham chiếu tham số Kết quả trên tác vụ. Cả hai điều này sẽ chặn chuỗi bắt đầu Tác vụ mà tôi không muốn.

Một số giải pháp tôi đã nghĩ:

  1. Tạo một chủ đề mới và bắt đầu nhiệm vụ trên đó, sau đó sử dụng Chờ() hoặc .Result để chặn các chủ đề mới và đồng bộ hóa kết quả lại cho người gọi bằng cách nào đó, có thể với việc bỏ phiếu cho các tham số IsCompleted.

  2. Có tác vụ 'Thông báo đã hoàn thành' mà tôi có thể bắt đầu sau khi hoàn thành tác vụ tôi muốn chạy, sau đó tăng sự kiện tĩnh hoặc một thứ gì đó.

  3. Chuyển đại biểu vào đầu vào của tác vụ và gọi thông báo đó để hoàn thành nhiệm vụ.

Tôi có thể nghĩ hoặc ưu tiên và chống lại tất cả, nhưng tôi đặc biệt không thích ý tưởng tạo chủ đề mới để bắt đầu nhiệm vụ khi mục đích sử dụng Lớp nhiệm vụ ở nơi đầu tiên là trừu tượng ra khỏi sử dụng Thread trực tiếp.

Bất kỳ suy nghĩ nào về cách tốt nhất? Tôi thiếu một cái gì đó đơn giản? Một sự kiện 'Đã hoàn thành' có quá nhiều để yêu cầu không :)? (Chắc chắn có lý do chính đáng tại sao không có!)

+0

Ngoài sự tò mò, tại sao không sử dụng BackgroundWorker? Nó có nhiệm vụ hoàn thành, cũng như thông báo hủy bỏ. – Robaticus

+1

'BackgroundWorker' không còn cần thiết bây giờ mà' Task' là với chúng tôi. BGW yêu cầu một 'SynchronizationContext', tùy chọn với' Task' (cho phép tính song song lớn hơn). –

Trả lời

26

I nghi ngờ bạn đang tìm kiếm Task.ContinueWith (hoặc Task<T>.ContinueWith). Về cơ bản, nói "Khi bạn hoàn thành tác vụ này, hãy thực hiện tác vụ này". Tuy nhiên, có nhiều tùy chọn khác nhau mà bạn có thể chỉ định để kiểm soát nhiều hơn.

MSDN đi vào chi tiết hơn về điều này trong "How to: Chain Multiple Tasks With Continuations""Continuation Tasks".

+0

Có, tôi hiểu điều đó, nhưng nó không giải quyết được vấn đề khi biết khi chuỗi nhiệm vụ đã kết thúc mà không cần gọi Task.Wait() (và do đó chặn) trên chuỗi bắt đầu nhiệm vụ. Một cách tiếp cận mà tôi nghĩ đến (như trên) là sử dụng Task.ContinueWith để kết nối một tác vụ làm tăng sự kiện mà các bên quan tâm có thể đăng ký. Điều này sẽ giữ nguyên nhiệm vụ ban đầu. –

+1

@bwilliams: Tại sao không chỉ vạch trần nhiệm vụ, và các bên quan tâm có thể gọi 'Task.ContinueWith'? Tôi không thấy trong cách nó * không * giải quyết vấn đề của biết khi nhiệm vụ đã hoàn thành ... đó là một cuộc gọi không chặn nói rằng, "Hãy gọi cho tôi trở lại khi điều này được hoàn thành." –

+1

(Hoặc thay vì phơi bày bản thân nhiệm vụ, bạn có thể cung cấp phương pháp của riêng bạn mà sau đó chỉ cần gọi 'ContinueWith' trong nội bộ. Đó là điều tương tự, thực sự.) –

4

Bạn có thể áp dụng task continuation.

Hoặc, Task thực hiện IAsyncResult, vì vậy bạn có thể sử dụng standard approaches for that interface (chặn, bỏ phiếu hoặc đợi trên WaitHandle).

+0

Đối với chủ đề tiếp tục công việc, xin vui lòng xem bình luận của tôi dưới bài viết của Jon Skeet. Chặn và bỏ phiếu Tôi không thích ý tưởng vì nó sẽ có nghĩa là phải bắt đầu một luồng khác để giữ cho chuỗi ban đầu bắt đầu nhiệm vụ đáp ứng. Tôi đã thấy tôi có thể sử dụng WaitHandle, nhưng tài liệu cho biết cách ưu tiên là sử dụng Task.Wait(). Điều đó nói rằng, vì điều đó không làm những gì tôi muốn có lẽ WaitHandle là tốt nhất cho tôi –

4

Trong C# hiện đại, bạn không còn cần phải gọi số ContinueWith() một cách rõ ràng. Một giải pháp thay thế cho câu trả lời được chấp nhận ban đầu là chỉ cần tạo phương thức asyncawait s Task được đề cập và thực hiện bất cứ điều gì muốn khi hoàn thành Task.Ví dụ: giả sử bạn muốn tăng sự kiện được gọi là TaskCompleted khi hoàn tất Task. Bạn sẽ viết một phương thức như:

async Task RaiseEventWhenTaskCompleted(Task task) 
{ 
    await task; 
    TaskCompleted?.Invoke(this, EventArgs.Empty); 
} 

Để "đăng ký" sự chờ đợi, chỉ cần gọi phương thức trên. Thêm xử lý ngoại lệ như mong muốn, hoặc trong phương thức ở trên hoặc trong một số mã mà cuối cùng sẽ quan sát được Task được trả về theo phương thức trên.

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