9

What are the differences between this two methods that seems to do the same thing? Can it be done even with async/await?

public Task<int> TaskMaxAsync1 ( Task<int>[] my_ints ) { return Task.WhenAll( my_ints ) .ContinueWith ( x => x.Result.Where ( i => i%2 != 0 ).Max( ) ) ; } public Task<int> TaskMaxAsync2 ( Task<int>[] my_ints ) { var numbers = Task.WhenAll( my_ints ).Result ; return Task.FromResult( numbers.Where( i => i%2 != 0 ).Max( ) ) ; } 
3
  • 1
    One difference would be that the one using .Result is prone to deadlocking - stackoverflow.com/questions/17248680/… Commented Aug 24, 2015 at 8:59
  • @LasseV.Karlsen They both use .Result Commented Aug 24, 2015 at 9:01
  • 5
    Agh, yes, ok, let me reword. The one using .Result outside of ContinueWith (ie. the second one) is prone to deadlocking. The only place it is safe to read .Result is from a task that is guaranteed to have completed. Reading .Result from a task that has not yet completed may deadlock. Commented Aug 24, 2015 at 9:01

3 Answers 3

8

Differences between Result and ContinueWith

Result will synchronously block until the task completes, and will wrap exceptions in an AggregateException.

ContinueWith will register a callback with the task, and invoke that callback when the task completes.

For asynchronous code, both Result and ContinueWith should be replaced by await.

Can it be done even with async/await?

Sure, like this:

public async Task<int> MaxAsync(Task<int>[] my_ints) { int[] ints = await Task.WhenAll(my_ints); return ints.Where(i => i % 2 != 0).Max(); } 
Sign up to request clarification or add additional context in comments.

Comments

7

What are the differences between this two methods that seems to do the same thing?

The difference is that the former returns a hot task to the caller, while the latter synchronously blocks, then re-wraps the result in a Task using Task.FromResult. The latter is also a common case for deadlocks, if you're running inside an environment that has a custom SynchronizationContext.

Can it be done even with async/await?

Yes, it can:

public async Task<int> MaxAsync(Task<int>[] myInts) { int[] results = await Task.WhenAll(myInts); return results.Max(i => i % 2 != 0 ? i : (int?)null) ?? 0; } 

Comments

3

task0.Result will synchronously block and wait for task0 to complete, while task1.ContinueWith will not wait for task1 to complete but returns a new Task(which will run when task1 completes) immediately.

So, the two methods in your example do not behave the same. In your second method, if my_ints were not all ran to complete when they were passed to the WhenAll method, the .Result will synchronously block the calling thread for whatever long time that all tasks within my_ints would take to finish, and if some of them throws exception, TaskMaxAsync2 throws.

However the first method will return immediately even my_ints would never finish or throw exception.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.