Andre Borges
Andre Borges

Reputation: 1442

How to properly wait for first completed task

I'm writing a simple console application that should make requests to different external sources and return the response from whichever source answers first.

I'm trying to do this using Task objects (to keep the code as simple as possible), but my program deadlocks and never completes execution. Now, I suspect that it's because I'm using Result on my tasks, but I have no idea how to make it work without the Result.

public static string GetResultFromAnySource()
{
    var t1 = new Task<string>(() => { Thread.Sleep(500); return "Result from source 1"; });
    var t2 = new Task<string>(() => { Thread.Sleep(100); return "Result from source 2"; });

    var res = Task.WhenAny(t1, t2).Result;

    if (res == t1)
        return "Source 1 was faster. Result: " + t1.Result;
    else if (res == t2)
        return "Source 2 was faster. Result: " + t2.Result;

    throw new ApplicationException("Something went very wrong");
}

static void Main(string[] args)
{
    Console.WriteLine(GetResultFromAnySource());
}

Any help is appreciated.

Upvotes: 0

Views: 3248

Answers (2)

Radin Gospodinov
Radin Gospodinov

Reputation: 2323

Hi Andre I rewrote your program by using async/await keywords:

class Program {
public static async Task<string> GetResultFromAnySource() {

  var t1 = Task<string>.Run( () => {  Task.Delay(500).Wait(); return "Result from source 1"; });
  var t2 = Task<string>.Run(() => { Task.Delay(100).Wait(); return "Result from source 2"; });

  var res = await Task.WhenAny(t1, t2);

  if (res == t1)
    return "Source 1 was faster. Result: " + await t1;
  else if (res == t2)
    return "Source 2 was faster. Result: " + await t2;

  throw new ApplicationException("Something went very wrong");
}

static void Main(string[] args) {

  Task.Run(async () => await Out()).Wait();
}

static async Task Out()
{
  var str = await GetResultFromAnySource();
  Console.WriteLine(str);
}

}

It is recommended to use Task.Run - the code is clear and it starts the task immediately.

Upvotes: 4

YK1
YK1

Reputation: 7622

You missed to start the tasks.

t1.Start();
t2.Start();

Alternatively, use Task.Run()

var t1 = Task.Run<string>(() => { Thread.Sleep(500); return "Result from source 1"; });
var t2 = Task.Run<string>(() => { Thread.Sleep(100); return "Result from source 2"; });

Upvotes: 3

Related Questions