gspeager
gspeager

Reputation: 25

Async function with two awaited async calls, where the 2nd needs the results from the first

So I have a function that looks like:

    async Task DoSomething() {
        var result = await GetDataForAsyncCall2();
        if (result != null) {
            await AsyncCall2(result.result1, result.result2);
        }
    }

My problem is that whenever I try to call it, it seems to return from the function after the GetDataForAsyncCall2() is called. But the actual result I want from the function is AsyncCall2.

Why would my function be returning after the first await, or how can I ensure the second await is ran before the function returns?

Upvotes: 1

Views: 1370

Answers (1)

Eric Lippert
Eric Lippert

Reputation: 659956

Why would my function be returning after the first await?

The fact that you are asking the question indicates that you must have some completely false beliefs about what await does. This is like asking why return returns. An await is a kind of return. (Just like yield return is a kind of return in an iterator block. yield return and await are at some level essentially the same thing; they are both points at which a workflow returns to its caller and signs up the remainder of the method to run in the future.)

You probably need to do some research as to what await actually means in C#. Briefly, await means "if the results of this task are not available then return to my caller so that it can keep working. Pick up at this point some time in the future after the task I'm waiting for is complete." That is, asynchronously wait for the task to complete.

If this is the first await you hit in the method then the thing returned to the caller will be a task representing the method itself, because now it is not complete either, and the caller probably wants to await it.

But that brief explanation is likely not enough. You should read some articles or tutorials on how this works so that you can use it more effectively.

how can I ensure the second await is ran before the function returns?

You don't. That's by design. Awaits allow you to identify the points in an asynchronous workflow that are (1) high latency operations, and (2) where the operation must be completed before the remainder of the workflow executes. The sequence of awaits you have correctly represents the data dependency of the second high-latency task on the first. The system is working as designed.

But the actual result I want from the function is AsyncCall2.

I assume that the "result" you are after is a side effect since no value is extracted from AsyncCall2, and you have a valueless task returned from the method.

That's precisely what you get. Your method returns a task and that task will be marked as completed at some point in the future after the task returned by AsyncCall2 is completed. If your caller wants to asynchronously wait for that time in the future then it should await the returned task.

Again: an await is a point in an asynchronous workflow where we know that before it, the task has likely not completed, and after it, it definitely has completed.

A question that you did not ask:

Should I solve my problem by synchronously waiting for the high latency operation using .Result or similar?

No. That not only defeats the entire purpose of using await to manage latency. It also can cause you to wait forever. See http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html for some examples.

These examples are highly educational; I would read them very carefully until you thoroughly understand how await works.

Upvotes: 5

Related Questions