TaskCompletionSource - Trying to understand threadless async work

后端 未结 2 1222
孤街浪徒
孤街浪徒 2020-12-22 21:35

I\'m trying to understand the purpose of TaskCompletionSource and its relation to async/threadless work. I think I have the general idea but I want to make sure

相关标签:
2条回答
  • 2020-12-22 21:43

    TaskCompletionSource is used to create Task objects that don't execute code.

    They're used quite a bit by Microsoft's new async APIs - any time there's I/O-based asynchronous operations (or other non-CPU-based asynchronous operations, like a timeout). Also, any async Task method you write will use TCS to complete its returned Task.

    I have a blog post Creating Tasks that discusses different ways to create Task instances. It's written from an async/await perspective (not a TPL perspective), but it still applies here.

    Also see Stephen Toub's excellent posts:

    • The Nature of TaskCompletionSource
    • Mechanisms for Creating Tasks
    • await anything; (using TaskCompletionSource to await anything).
    • Using Tasks to implement the APM Pattern (creating Begin/End using TaskCompletionSource).
    0 讨论(0)
  • 2020-12-22 21:58

    I like the explanation which was provided in http://tutorials.csharp-online.net/TaskCompletionSource

    (sorry, the link may be dead at the moment)

    First two paragraphs are below

    We've seen how Task.Run creates a task that runs a delegate on a pooled (or non-pooled) thread. Another way to create a task is with TaskCompletionSource.

    TaskCompletionSource lets you create a task out of any operation that starts and finishes some time later. It works by giving you a "slave" task that you manually drive—by indicating when the operation finishes or faults. This is ideal for I/O- bound work: you get all the benefits of tasks (with their ability to propagate return values, exceptions, and continuations) without blocking a thread for the duration of the operation.

    To use TaskCompletionSource, you simply instantiate the class. It exposes a Task property that returns a task upon which you can wait and attach continuations—just as with any other task. The task, however, is controlled entirely by the TaskCompletionSource object via the following methods:

    public class TaskCompletionSource<TResult> 
    { 
     public void SetResult(TResult result); 
     public void SetException (Exception exception); 
    
     public void SetCanceled();   
     public bool TrySetResult (TResult result); 
     public bool TrySetException (Exception exception); 
     public bool TrySetCanceled();
     ... 
    }
    

    Calling any of these methods signals the task, putting it into a completed, faulted, or canceled state (we'l cover the latter in the section "Cancellation"). You'e supposed to call one of these methods exactly once: if called again, SetResult, SetException, or SetCanceled will throw an exception, whereas the Try* methods return false.

    The following example prints 42 after waiting for five seconds:

    var tcs = new TaskCompletionSource<int>();
    new Thread (() =>     {
                           Thread.Sleep (5000); 
                           tcs.SetResult (42); 
                          })    
               .Start();   
    Task<int> task = tcs.Task;    // Our "slave" task. 
    Console.WriteLine(task.Result);  // 42
    

    Other interesting quotes

    The real power of TaskCompletionSource is in creating tasks that don't tie up threads.

    .. and later on

    Our use of TaskCompletionSource without a thread means that a thread is engaged only when the continuation starts, five seconds later. We can demonstrate this by starting 10,000 of these operations at once without error or excessive resource consumption:

    0 讨论(0)
提交回复
热议问题