Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard pattern to follow when waiting for N number of async methods to complete?

public class FooDataRepository
{
    private MyServiceReferenceClient Client { get; set; }

    public void FooClass()
    {
        Client = new MyServiceReferenceClient();
        Client.SaveFooCompleted += Client_SaveFooCompleted;
        Client.SaveBarCompleted += Client_SaveBarCompleted;
    }

    private void Client_SaveFooCompleted(Object sender, EventArgs e) { ... }

    private void Client_SaveBarCompleted(Object sender, EventArgs e) { ... }

    public void SaveFoo(Foo foo)
    {
        Client.SaveFooAsync(foo);

        foreach (var bar in foo.Bars)
            Client.SaveBarAsync(bar);
    }

}

I want to do something within the FooDataRepository class once the SaveFooAsync and the all the SaveBarAsync methods have completed. Is there a standard pattern for trying to do a single thing based upon N number of Async calls completing?

like image 380
michael Avatar asked Jun 29 '11 16:06

michael


2 Answers

You can use TaskFactory.ContinueWhenAll to schedule a code to run when all tasks have completed.

Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//This will not block.
Task.Factory.ContinueWhenAll(tasks, completedTasks => { RunSomeMethod(); });

EDIT:

Regarding your question about composing async method calls with tasks if the class has Begin/End methods for calling the method in an async way you can use Task.FromAsync

Alternatively you can also use Rx for calling several methods asynchronously and then observing when all of them have completed. Have a look at this question: Can I shortcut the Begin/End async pattern by using an event to create my AsyncResult? (C# .Net 3.5, WCF)

like image 68
Giorgi Avatar answered Sep 22 '22 15:09

Giorgi


If you can, use Tasks and then do Task.WaitAll. E.g.:

Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//Block until all tasks complete.
Task.WaitAll(tasks);

// Continue on this thread...

If you don't have access to the synchronous methods, you can use a method like the one described at Tasks and the Event-based Asynchronous Pattern to convert your EAP library into one that uses tasks. Alternately, Rx provides several ways to deal with this issue.

Basically, the best practice advice is to use Tasks if you can. If your application requires more fine-grained control, look seriously into Rx - it provides LINQ filtering for events and async methods.

like image 38
Pat Avatar answered Sep 23 '22 15:09

Pat