20
votes

I have a method that returns a List<> of an object. This method takes a while to run.

private List<MyObject> GetBigList()
{
    ... slow stuff
}

This method is called from 4 or 5 sources. So, I thought I would try and use async and await to keep things moving while this list builds. I added this method:

public async Task<List<MyObject>> GetBigListAsync()
{
    var resultsTask = GetBigList();
    var resuls = await resultsTask;
    return resuls;
}

But, on this line:

var resuls = await resultsTask;

I get this error:

List<MyObject> does not contain a definition for GetAwaiter, and no extension method 'GetAwaiter' accepting a first argument of type List<MyObject> could be found.

What am I missing?

3
Your example code does not show any use of a Task in the GetBigList method nor is it marked as async, and that means the result from that method cannot be awaited.Travis J
try async Task<List<MyObject>> GetBigList()Mate
Remember, await does not make a synchronous operation into an asynchronous operation. Await signs up the remainder of the current method as the continuation of an already existing asynchronous operation. Await is about managing asynchrony, not creating it. If you want a synchronous operation to be asynchronous, you're going to have to figure out a way to make that happen.Eric Lippert
I think This Link My Help You List.add() async task await correct syntaxMostafa Anssary

3 Answers

37
votes

It seems you're a newbee to async-await. What really helped me to understand what async-await does is the restaurant analogy given by Eric Lippert in this interview. Search somewhere in the middle for async await.

Here he describes that if a cook has to wait for something, instead of doing nothing he starts looking around to see if he can do something else in the meantime.

Async-await is similar. Instead of awaiting for a file to be read, a database query to return, a web page to be downloaded, your thread will go up the callstack to see if any of the callers are not awaiting and performs those statements until he sees an await. Once he sees the await the thread goes up the call stack again to see if one of the callers is not awaiting etc. After a while when the file is read, or the query is finished etc, the statements after the await are performed.

Normally while reading your big list your thread would be very busy instead of idly waiting. It's not certain that ordering another thread to do the stuff would improve the time needed to read your list. Consider measuring both methods.

One reason to use async-await, even if it would lengthen the time needed to read the big list, would be to keep the caller (user interface?) responsive.

To make your function async, you should do the following:

  • Declare the function async;
  • Instead of TResult return Task<TResult> and instead of void return Task;
  • If your function calls other async functions, consider remembering the returned task instead of await, do other useful stuff you need to do and await the task when you need the result;
  • If you really want to let another thread do the busy stuff. call

    Task.Run( () => GetBigList())

and await when you need the results.

private async Task<List<MyObject>> GetBigListAsync()
{
    var myTask = Task.Run( () => GetBigList());
    // your thread is free to do other useful stuff right nw
    DoOtherUsefulStuff();
    // after a while you need the result, await for myTask:
    List<MyObject> result = await myTask;

    // you can now use the results of loading:
    ProcessResult(result);
    return result;
}

Once again: if you have nothing useful to do while the other thread is loading the List (like keeping UI responsive), don't do this, or at least measure if you are faster.

Other articles that helped me understanding async-await were - Async await, by the ever so helpful Stephen Cleary, - and a bit more advanced: Async-Wait best practices.

16
votes

resultTask is just the list returned from GetBigList(), so nothing will happen async there.

What you can do is offload the task to a separate thread on the threadpool by using Task.Run and return the awaitable Task object:

// Bad code
public Task<List<MyObject>> GetBigListAsync()
{
    return Task.Run(() => GetBigList());
}

While above example best matches what you were trying to do, it is not best practice. Try to make the GetBigList() async by nature or if there really is no way, leave the decision about executing the code on a separate thread to the calling code and don't hide this in the implementation F.e. if the calling code already runs async, there is no reason to spawn yet another thread. This article describes this in more detail.

11
votes

A couple of years later but I feel it is worth to add for the collection, once people search for the resolution since .NET has changed quite a bit:

return await Task.FromResult(GetBigList())