Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task chaining without TaskCompletionSource?

I'm converting some async/await code to chained tasks, so I can use it in the released framework. The await code looks like this

public async Task<TraumMessage> Get() {
  var message = await Invoke("GET");
  var memorized = await message.Memorize();
  return memorized;
}

where

Task<TraumMessage> Invoke(string verb) {}
Task<TraumMessage> Memorize() {}

I was hoping to chain Invoke and Memorize to return the task produced by Memorize, but that results in a Task<Task<TraumMessage>. The solution i've ended up is a TaskCompletionSource<TraumMessage> as my signal:

public Task<TraumMessage> Get() {
  var completion = new TaskCompletionSource<TraumMessage>();
  Invoke("GET").ContinueWith( t1 => {
     if(t1.IsFaulted) {
       completion.SetException(t1.Exception);
       return;
     }
     t1.Result.Memorize().ContinueWith( t2 => {
       if(t2.IsFaulted) {
         completion.SetException(t2.Exception);
         return;
       }
       completion.SetResult(t2.Result);
     });
  });
  return completion.Task;
}

Is there a way to accomplish this without the TaskCompletionSource?

like image 913
Arne Claassen Avatar asked Jul 30 '11 16:07

Arne Claassen


People also ask

What is the use of TaskCompletionSource?

Run turns something synchronous into a Task (by running it on a separate thread), TaskCompletionSource turns something that is already asynchronous into a Task . "If it is already asynchronous, why does it need to be turned into a Task ?"

Is TaskCompletionSource thread safe?

Is it safe to pass non-thread-safe objects created on one thread to another using TaskCompletionSource. SetResult()? Yes, as long as the object can be used on a different thread than the one it was created on (of course).

Does Task create new thread?

Task is more abstract then threads. It is always advised to use tasks instead of thread as it is created on the thread pool which has already system created threads to improve the performance. The task can return a result. There is no direct mechanism to return the result from a thread.

Is Task run parallel C#?

Task parallelism is the process of running tasks in parallel. Task parallelism divides tasks and allocates those tasks to separate threads for processing.


2 Answers

Yes, the framework comes with a handy Unwrap() extension method for exactly what you want.

Invoke("GET").ContinueWith( t => t.Result.Memorize() ).Unwrap();

If you're doing cancellation then you'll need to pass cancel tokens into the appropriate places, obviously.

like image 76
John Doty Avatar answered Oct 04 '22 02:10

John Doty


I think that's pretty much the only way to accomplish what you want. Chaining disparate Tasks together isn't supported by the continuation APIs, so you have to resort to using a TaskCompletionSource like you have to coordinate the work.

I don't have the Async CTP installed on this machine, but why don't you take a look at the code with a decompiler (or ILDASM if you know how to read IL) to see what it's doing. I bet it does something very similar to your TCS code under the covers.

like image 27
Drew Marsh Avatar answered Oct 04 '22 03:10

Drew Marsh