I would like to populate a collection using collection initializer that will call async methods:
public class Diagnostics
{
public async Task<IEnumerable<DiagnosticsInfo>> Get() => new List<DiagnosticsInfo>
{
await GetDiagnosticsInfo1(),
await GetDiagnosticsInfo2(),
await GetDiagnosticsInfo3()
};
}
The aim is for all the GetDiagnosticsInfoX() methods to execute in parallel.
I have a suspicion that the generated code will invoke GetDiagnosticsInfoX() methods synchronously - it will await the first call before invoking the second.
Is my gut feel correct?
If so I assume I would need to await all the tasks like this:
public class Diagnostics
{
public async Task<IEnumerable<DiagnosticsInfo>> Get()
{
var task1 = GetDiagnosticsInfo1();
var task2 = GetDiagnosticsInfo2();
var task3 = GetDiagnosticsInfo3();
await Task.WhenAll(task1, task2, task3);
return new List<DiagnosticsInfo> {task1.Result, task2.Result, task3.Result};
}
}
Is my gut feel correct?
Your gut feeling is right. All collection initializer does is invoke the Add method for the collection. This means your code is translated to:
public async Task<IEnumerable<DiagnosticsInfo>> Get()
{
var list = new List<DiagnosticsInfo>();
list.Add(await GetDiagnosticsInfo1());
list.Add(await GetDiagnosticsInfo2());
list.Add(await GetDiagnosticsInfo3());
return list;
}
Using Task.WhenAll will wait for all async methods to complete. You can then return the array you receive:
public async Task<IEnumerable<DiagnosticsInfo>> Get()
{
var task1 = GetDiagnosticsInfo1();
var task2 = GetDiagnosticsInfo2();
var task3 = GetDiagnosticsInfo3();
return await Task.WhenAll(task1, task2, task3);
}
Related
If I have code that says:
public async Task Test1()
{
Task task1 = MakeEggAsync();
Task task2 = MakeBaconAsync();
await Task.WhenAll(task1, task2);
}
async Task MakeBaconAsync()
{
while (CookIsBusy)
{
//
await Task.Delay(100);
}
}
async Task MakeEggAsync()
{
await makeEgg2Async();
}
async Task makeEgg2Async()
{
while (CookIsBusy)
{
//
await Task.Delay(100);
}
}
...will the computer return to the main Test1() after it get to this line?
async Task MakeEggAsync()
{
await makeEgg2Async();
}
...or will it return only after it get to a delay? I know with threading it only returns after you get to a wait.
Sorry I am new to this and I am trying to learn.
Does the computer returns after it gets to an await or after it get to a Task.Delay? This is what I am really asking.
Every async method begins executing synchronously.
Also, objects are awaited, not methods. In other words, this code:
async Task MakeEggAsync()
{
await makeEgg2Async();
}
is roughly the same as this code:
async Task MakeEggAsync()
{
var task = makeEgg2Async();
await task;
}
So the computer returns to Test1 after the Task.Delay is invoked.
We are running into a situation where have a requirement to start and execute few launch and forget threads during a call. Though, our call fails to execute if the async methods have any awaited call.
Here is an example. Are we missing something?
public class SomeClass
{
public async Task Test()
{
//Calling synchronously this things works
await Save(1).ConfigureAwait(false);
await Save(2).ConfigureAwait(false);
await Save(3).ConfigureAwait(false);
//Starting three threads at the same time fails while trying to run var queryResult = await SomeClient.QueryAsync<T>(q).ConfigureAwait(false);
_ = Task.Run(async () => await Save(1));
_ = Task.Run(async () => await Save(2));
_ = Task.Run(async () => await Save(3));
}
public async Task<bool> Save(int ct)
{
var x = await Update(ct).ConfigureAwait(false);
return x;
}
public async Task<bool> Update(int ct)
{
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
return true;
}
}
public class SomeObject
{
public async Task<T> CallingSomeAsyncMethod(string q)
{
await Task.Delay(1000).ConfigureAwait(false);
//OR Any async method which is awaited here just stops the execution
return queryResult;
}
}
If you want to run multiple tasks at the same time you should call the methods without the await and hold the task. Then you can do await Task.WhenAll(task1, task2, task3, ...);
I have multiple Async methods that I can run one by one but When I Use Task.WhenAll, I really don't know how to get the result. Following are my Async methods
public async Task<IEnumerable<MyModel>> Method1Async()
{
return await Task<IEnumerable<MyModel>>.Run<IEnumerable<MyModel>>(() => GetMethod1Data());
}
//Here Method1Async().Result will get me the data but don't know how to get the result when I am using Task.WhenAll()
public async Task<IEnumerable<MyModel>> Method2Async()
{
return await Task<IEnumerable<MyModel>>.Run<IEnumerable<MyModel>>(() => GetMethod2Data());
}
public async Task<IEnumerable<MyModel>> Method3Async()
{
return await Task<IEnumerable<MyModel>>.Run<IEnumerable<MyModel>>(() => GetMethod3Data());
}
And here is my code where I am using Task.WhenAll
public async Task GetDataAsync()
{
Task[] tasks = new Task[3];
tasks[0] = Method1Async();
tasks[1] = Method2Async();
tasks[2] = Method2Async();
await Task.WhenAll(tasks).ConfigureAwait(false);
}
Now if I call
GetDataAsync()
method, I get all ok but don't know how to get the result from the returned task?
It will return an Array of type IEnumerable<MyModel> so you can set the return type of your async method to that :
public Task<IEnumerable<MyModel>[]> GetDataAsync()
{
Task[] tasks = new Task[3];
tasks[0] = staticDataService.Method1Async();
tasks[1] = staticDataService.Method2Async();
tasks[2] = staticDataService.Method3Async();
return Task.WhenAll(tasks);
}
and then consume it:
IEnumerable<MyModel>[] results = await GetDataAsync();
I want to have an async method in my call that would be called by my library consumers with an await. But the internal working of my method, while I need it to run on a separate thread, does not call any other await on it's own.
I just do the work the method is supposed to do and return the type. And the compiler warns me that this method will not run in an async way.
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
On the other hand, if I write a method that starts a new task using TaskFactory like this:
public Task<MyResultObject> DoSomeWork()
{
return Task<MyResultObject>.Factory.StartNew(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
Then I cannot call it using the await keyword like this await DoSomeWork().
How do I write an async (must be async and not task with result or wait) without using some await call inside?
You can do this
public Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return Task.FromResult(result);
}
which is exactly the same as
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
Only this version gives a warning and has slightly more overhead.
But neither will run on another thread. The only benefit is that they have an awaitable interface.
To do it in parallel, your code is Ok but Task.Run is preferred over StartNew():
public Task<MyResultObject> DoSomeWork()
{
return Task.Run(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
And in all these cases you can definitely await DoSomeWork()
I have a method with some code that does an await operation:
public async Task DoSomething()
{
var x = await ...;
}
I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:
public async Task DoSomething()
{
App.Current.Dispatcher.BeginInvoke(async () =>
{
var x = await ...;
}
);
}
On the inner async, I get the error:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.
How can I work with async from within Dispatcher.BeginInvoke()?
The other answer may have introduced an obscure bug. This code:
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.
You are probably looking for something like this:
public async Task<int> DoSomethingWithUIAsync()
{
await Task.Delay(100);
this.Title = "Hello!";
return 42;
}
public async Task DoSomething()
{
var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
DoSomethingWithUIAsync);
Debug.Print(x.ToString()); // prints 42
}
In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.
Alternatively, use one of Dispatcher.InvokeAsync methods.
I think you can use below code and then depends of place use it with async and await or without to fire and forget:
public static Task FromUiThreadAsync(Action action)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Dispatcher disp = GetUiDispatcher();
disp.Invoke(DispatcherPriority.Background, new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}));
return tcs.Task;
}
Use Dispatcher.Invoke()
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
(Edit: This answer is wrong, but I'll fix it soon)
Declare this
public async Task DoSomethingInUIThreadAsync(Func<Task> p)
{
await Application.Current.Dispatcher.Invoke(p);
}
Use like this
string someVar = "XXX";
DoSomethingInUIThreadAsync(()=>{
await Task.Run(()=> {
Thread.Sleep(10000);
Button1.Text = someVar;
});
});
DoSomethingInUIThreadAsync receives a delegate that returns a Task, Application.Current.Dispatcher.Invoke accepts a Func callback that can be awaited.