0

I am trying to process each async task result when/as they complete. These tasks have different result sets. I like to execute these tasks concurrently but need to process the result when any finishes.

There are many google search results when async functions have the same return type, however, I couldn't get my hand to one with different result sets.

private async Task CompleteTasksAsync()
{
    var taskA = GetStringAsync();
    var taskB = GetIntAsync();
    var taskC = GetStringListAsync();
    var taskD = GetGenericAsync<double>(1d);

    //var tasks = new[] {taskA, taskB, taskC, taskD} // this will only work if all
                                                     // tasks have same return type

    await Task.WhenAll(taskA, taskB, taskC, taskD); // This statement will wait
                                                    // until all tasks are completed

    // when Task A finished Console.WriteLine(taskA.Result);
    // when Task B finished Console.WriteLine(taskB.Result);
    // when Task C finished Console.WriteLine(taskC.Result);
    // when Task D finished Console.WriteLine(taskD.Result);
}

private Task<string> GetStringAsync() => Task.FromResult("string");
private Task<int> GetIntAsync() => Task.FromResult(1);
private Task<List<string>> GetStringListAsync()
    => Task.FromResult(new List<string> { "string"});
private Task<T> GetGenericAsync<T>(T data) => Task.FromResult(data);
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
ARH
  • 1,566
  • 3
  • 25
  • 56
  • You understand that these are not literally running concurrently, right? These are co-routines. They're all sharing a single thread. – Tim Roberts Feb 23 '23 at 22:39
  • 1
    @TimRoberts we don't know that. This is fairly clearly pseudo code to help explain the question. As long as his real code doesn't do any IO or CPU work synchronously, it is running in parallel – Josh Heaps Feb 23 '23 at 22:47
  • @ARH, just a shot in the dark here, but, maybe try just moving everything you're doing with that information to the same async method. It's probably a dumb suggestion, but I thought I'd throw it out there – Josh Heaps Feb 23 '23 at 22:52
  • This is just a clean example, the real one doesn't have any IO operation. – ARH Feb 23 '23 at 22:53
  • What is confusing with your question is that you want to process the tasks as they complete, and the tasks in your example are all completed upon creation. Which begs the question: between equally completed tasks, are some more completed than others? – Theodor Zoulias Feb 24 '23 at 06:36
  • Also does the example reflect accurately what you want to do with the tasks when they complete? Do you really intend to pass their result in a method that has an `object` parameter, like the `Console.WriteLine`? – Theodor Zoulias Feb 24 '23 at 06:42
  • Actually, I was looking for a generic solution rather than ifs. In this example, I need to have the result and then according to the need, all the results are logged. Every task returns an object of a model (a different model depending on the task). All the results goes to ProessResultAsync(T data){...} – ARH Feb 24 '23 at 18:54
  • This question might be relevant: [How to create pass through Task.ContinueWith](https://stackoverflow.com/questions/52138702/how-to-create-pass-through-task-continuewith). Also [this answer](https://stackoverflow.com/questions/62233591/task-continuewith-executing-but-task-status-is-still-running/62237760#62237760) (in another question). – Theodor Zoulias Feb 25 '23 at 12:55

2 Answers2

1

The simple answer is to write more async methods;

public async Task ProcessString(){
    var str = await GetStringAsync();
    DoSomething(str);
}

await Task.WhenAll(
    ProcessString(), 
    ProcessInt(),
    ...
);
Jeremy Lakeman
  • 9,515
  • 25
  • 29
0

Finally, For anyone who want to do it without the if/switch. I used Dictionary<TAsk, Action> and this helped me to shape the tasks and results.

private async Task CompleteTasksAsync()
{
   var taskA = GetStringAsync();
   var taskB = GetIntAsync();
   var taskC = GetStringListAsync();
   var taskD = GetGenericAsync<double>(1d);

   Dictionary<Task, Action> tasks = new()
   {
     {taskA, () => Console.WriteLine(taskA.Result)},
     {taskB, () => Console.WriteLine(taskB.Result)  },       {taskC, () => Console.WriteLine(taskC.Result) },
     {taskD, () => Console.WriteLine(taskD.Result) }
   };

   while (tasks.Any())
   {
      var completedTask = await Task.WhenAny(tasks.Keys);

      tasks[completedTask]();

      tasks.Remove(completedTask);
  }

}
ARH
  • 1,566
  • 3
  • 25
  • 56