简体   繁体   中英

C# How to await async task until it indicates to proceed

I have a C# method, which calls an external web service multiple times, in a loop. I need to call it asynchronously in a different thread.

But the caller process MUST wait until the async thread meets a certain condition, - this condition occurs much before the loop iterations complete.

Please suggest a C# code example which describes how to wait until the async block of code indicates that a certain condition has been met, so that the main process can proceed without waiting for loop to finish.

My code:

..
List<MyObject> objList = GetObjects();
int counter = 0;
await Task.Factory.StartNew(() =>
{
    foreach (MyObject obj in objList)
    {
        counter++;
        CallExtWebSvc(obj);
        if (counter == 1)
        {
            // return an indication that main process can proceed.
        }
    }
});

// Do other stuff...

You could execute your method as fire and forget and then wait for a TaskCompletionSource. This TaskCompletionSource is given to the method that calls the webservice as parameter. The method then sets a result on the TaskCompletionSource at some point.

Here is an example code piece:

        public async Task DoWebserviceStuffAsync(TaskCompletionSource<bool> taskCompletionSource)
        {
            for (int i = 0; i < 10; i++)
            {
                //your webservice call
                await Task.Delay(5000);

                //some condition
                if (i == 1)
                {
                    //after setting this your CallingMethod finishes 
                    //waiting the await taskCompletionSource.Task;
                    taskCompletionSource.TrySetResult(true);
                }
            }
        }

        private async Task CallerMethod()
        {
            var taskCompletionSource = new TaskCompletionSource<bool>();

            //call method without await
            //care: You cannot catch exceptions without await
            DoWebserviceStuffAsync(taskCompletionSource);

            //wait for the DoWebserviceStuffAsync to set a result on the passed TaskCompletionSource
            await taskCompletionSource.Task;
        }

If you want to avoid the danger of "fire and forget" or you also need to wait for the full operation to complete, you could return two tasks (Task,Task) (C# v7 syntax). The caller would await both tasks in order.

public async Task Caller()
{
    var (partOne,partTwo) = DoSomethingAsync();

    await partOne;
    //part one is done...

    await partTwo;
    //part two is done...
}

public (Task,Task) DoSomethingAsync()
{
    var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
    return (tcs.Task, DoWork(tcs));
}

public async Task DoWork(TaskCompletionSource<bool> tcs)
{
    List<MyObject> objList = GetObjects();
    int counter = 0;
    await Task.Run(() =>
    {
        foreach (MyObject obj in objList)
        {
            counter++;
            CallExtWebSvc(obj);
            if (counter == 1)
            {
                // return an indication that main process can proceed.
                tcs.SetResult(true);
            }
        }
    });

    // Do other stuff...
}

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