简体   繁体   中英

Prevent async method from returning until all tasks are completed

So I'm still trying to understand the async/await pattern, but I'm also trying to achieve the following behavior:

A method A calls method B which runs a number of processes. Some of those processes can be run on separate threads while other things are being processed so that their return values will be available closer to when they are needed. Method B needs to not return control to the caller until all of these processes are completed.

Here is the test code that I am working with:

static void Main(string[] args)
{
    CallProc();
    Console.WriteLine("Program finished");
    Console.ReadKey();
}

public static async Task CallProc()
{
    var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
    var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
    var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));

    // some process happens here

    var oneMessage = await one; // waits until one finishes and then snags it's value
    Console.WriteLine("Got message {0}", oneMessage);

    // some more stuff happens here

    var twoMessage = await two; // waits until two is finished and then snags it's value
    Console.WriteLine(twoMessage);

    // TODO: need to make sure that everything is completed before returning control to caller
}

public static string SomeSynchronousProcessIDontOwn(int delayTime, string message, bool delay = true)
{
    Console.WriteLine("Starting \"{0}\"", message);
    if(delay) Thread.Sleep(delayTime);
    return string.Format("Finished \"{0}\"", message);
}

Right now, what is happening is that everything words as I expected except that the method is returning before everything is finished, so the output shows "Program finished" while "two" is still running.

How do I write this so that CallProc() can execute those tasks asynchronously but delay returning until everything has been completed. In other words, CallProc() needs to run some tasks asynchronously, but CallProc() itself needs to be called synchronously.

The idea of an asynchronous method, which is what you've written is that it will return control (approximately) immediately and the task that it returns will be marked as completed when the operation that it conceptually represents finishes.

This means that your program should either be looking at the resulting task to see when it finishes, or that you don't want an asynchronous method in the first place, and you should re-write CallProc synchronously rather than asynchronously.

To make CallProc synchronous simply remove async (and adjust the return type accordingly), and wait on each task instead of using await .

If CallProc really should be asynchronous then the caller should be adding a continuation (or using await ) to perform an action when the task is completed, rather than when the method returns.

Instead of awaiting each task individually why not just await all of them using WhenAll

public static async Task CallProc()
{
    var two = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(5000, "two"));
    var one = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(500, "one"));
    var three = Task.Factory.StartNew(() => SomeSynchronousProcessIDontOwn(1500, "three"));

    // run synchronous tasks

    await Task.WhenAll(one, two, three);
}

If you would prefer to have CallProc block (ie not return until all tasks have finished) then remove the async declaration and use Task.WaitAll instead.

public static void CallProc()
{
    // start tasks

    Task.WaitAll(one, two, three);
}

One way to do this is to simply call Wait() on the result of CallProc . This will essentially wait for the task returned by CallProc to finish before it continues. Calling Wait in a GUI app can cause a deadlock but for a console app it is fine.

static void Main(string[] args)
{
    CallProc().Wait();
    Console.WriteLine("Program finished");
    Console.ReadKey();
}

That will ensure that "Program finished" is printed after task two is finished.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM