From below 2 scenario(s), which one of them is correct way of doing asynchronous programming in c#?
Scenario-1
public async Task<T1> AddSomethingAsync(param)
{
return await SomeOtherFunctionFromThirdPartyLibraryForIOAsync(param);
}
then
List<Task> Tasks=new List<Task>();
foreach(var task in FromAllTasks())
{
Tasks.Add(AddSomethingAsync(task));
}
await Task.WhenAll(Tasks.AsParallel());
Scenario-2
public async Task<T1> AddSomethingAsync(param)
{
return SomeOtherFunctionFromThirdPartyLibraryForIOAsync(param);
}
then
List<Task> Tasks=new List<Task>();
foreach(var task in FromAllTasks())
{
Tasks.Add(SomeOtherFunctionFromThirdPartyLibraryForIOAsync(task));
}
await Task.WhenAll(Tasks.AsParallel());
The only difference between 2 is, later is not having await keyword inside AddSomethingAsync function.
So here is the update - What I want to know to achieve is, All tasks should be executed in parallel and asynchronously. (My thinking is in scenario-1, the call will be awaited inside AddSomethingAsync and will hurt at upper layer blocking next loop to execute. confirm
Scenario 3
public Task<T1> AddSomethingAsync(param)
{
return SomeOtherFunctionFromThirdPartyLibraryForIOAsync(param);
}
then
List<Task> Tasks=new List<Task>();
foreach(var task in FromAllTasks())
{
Tasks.Add(SomeOtherFunctionFromThirdPartyLibraryForIOAsync(task));
}
await Task.WhenAll(Tasks);
If you are not awaiting anything - you don't need async keyword. Doing AsParallel will do nothing in this case too.
In my opinion it's same. await is a mark, means this line execute in the same thread with this method, it'll await in thread.
Actually async and await is design for method return void. so if this method doesn't return result, it's can be put in a thread alone. Any async methods this method called means it'll use same thread with the void method, if thoese sub method need result await, it's wait inside this thread.
And when you put them in List<Task>, it's make no difference.
Related
A class has async method MonitorAsync(), which starts a long-running parallel operation. I have a collection of these monitors; these are all kicked off as follows:
internal async Task RunAsync()
{
var tasks = monitors.Select((p) => p.Value.MonitorAsync());
await Task.WhenAll(tasks);
}
If a monitor falls over, I need to know (basically I will run it up again). I've looked into ContinueWith and so on but when running a bunch of async tasks in parallel, how can I ensure I definitely know when one ends?
For context, RunAsync is basically the core of my application.
If a monitor falls over, I need to know (basically I will run it up again).
The easiest way to do this is to define this logic in a separate method:
internal async Task RunAsync()
{
var tasks = monitors.Select(p => MonitorAndRestart(p));
await Task.WhenAll(tasks);
async Task MonitorAndRestart(P p)
{
while (true)
{
try { await p.Value.MonitorAsync(); }
catch { ... }
p.Restart();
}
}
}
If you want to know when one ends (and that does not affect the others), ContinueWith() could be the way.
Alternatively, how about WaitAny in a loop?
while(anyTaskUnfinished){
await Task.WaitAny(tasks);
}
//Stuff you do after WhenAll() comes here
I am uncertain if you have to remove already finished Tasks. Or if it waits for any newly finishing.
You can try this:
If you do not want to call the Task.Wait method to wait for a task's completion, you can also retrieve the AggregateException exception from the task's Exception property
internal async Task RunAsync()
{
var tasks = monitors.Select((p) => p.Value.MonitorAsync());
try
{
await Task.WhenAll(tasks);
}
catch (Exception)
{
foreach (var task in tasks.Where(x => x.IsFaulted))
foreach (var exception in task.Exception.InnerExceptions)
{
// Do Something
}
}
}
Reference: Exception handling (Task Parallel Library)
I want to call an asynchronous method multiple times in a xUnit test and wait for all calls to complete before I continue execution. I read that I can use Task.WhenAll() and Task.WaitAll() for precisely this scenario. For some reason however, the code is deadlocking.
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = _fixture.CreateMany<LdapEntryDto>(2).ToList();
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = _attributesServiceClient.CreateLdapEntry(led);
task.Start();
creationTasks.Add(task);
}
Task.WaitAll(creationTasks.ToArray()); //<-- deadlock(?) here
//await Task.WhenAll(creationTasks);
var result = await _ldapAccess.GetLdapEntries();
result.Should().BeEquivalentTo(ldapEntries);
}
public async Task<LdapEntryDto> CreateLdapEntry(LdapEntryDto ldapEntryDto)
{
using (var creationResponse = await _httpClient.PostAsJsonAsync<LdapEntryDto>("", ldapEntryDto))
{
if (creationResponse.StatusCode == HttpStatusCode.Created)
{
return await creationResponse.Content.ReadAsAsync<LdapEntryDto>();
}
throw await buildException(creationResponse);
}
}
The system under test is a wrapper around an HttpClient that calls a web service, awaits the response, and possibly awaits reading the response's content that is finally deserialized and returned.
When I change the foreach part in the test to the following (ie, don't use Task.WhenAll() / WaitAll()), the code is running without a deadlock:
foreach (var led in ldapEntries)
{
await _attributesServiceClient.CreateLdapEntry(led);
}
What exactly is happening?
EDIT: While this question has been marked as duplicate, I don't see how the linked question relates to this one. The code examples in the link all use .Result which, as far as I understand, blocks the execution until the task has finished. In contrast, Task.WhenAll() returns a task that can be awaited and that finishes when all tasks have finished. So why is awaiting Task.WhenAll() deadlocking?
The code you posted cannot possibly have the behavior described. The first call to Task.Start would throw an InvalidOperationException, failing the test.
I read that I can use Task.WhenAll() and Task.WaitAll() for precisely this scenario.
No; to asynchronously wait on multiple tasks, you must use Task.WhenAll, not Task.WaitAll.
Example:
[Fact]
public async Task GetLdapEntries_ReturnsLdapEntries()
{
var ldapEntries = new List<int> { 0, 1 };
var creationTasks = new List<Task>();
foreach (var led in ldapEntries)
{
var task = CreateLdapEntry(led);
creationTasks.Add(task);
}
await Task.WhenAll(creationTasks);
}
public async Task<string> CreateLdapEntry(int ldapEntryDto)
{
await Task.Delay(500);
return "";
}
Task.WaitAll() will deadlock simply because it blocks the current thread while the tasks are not finished (and since you are using async/await and not threads, all of your tasks are running on the same thread, and you are not letting your awaited tasks to go back to the calling point because the thread they are running in -the same one where you called Task.WaitAll()-, is blocked).
Not sure why WhenAll is also deadlocking for you here though, it definitely shouldn't.
PS: you don't need to call Start on tasks returned by an async method: they are "hot" (already started) already upon creation
Let's consider the next procedures hierarhy
Main.cs:
// timer callback
{
Plot.UpdateData();
}
Plot.cs:
public async void UpdateData()
{
await CalculateData();
// ...
}
private async Task CalculateData()
{
await Calculations.Calculate();
// UI updating
// ...
}
Calculations.cs:
public static async Task<bool> Calculate()
{
async Task<bool> CalculateLR()
{
var task1 = Calculate1();
var task2 = Calculate2();
await Task.WhenAll(new[] { task1, task2 });
return true;
}
var leftTask = CalculateLR();
var rightTask = CalculateLR();
await Task.WhenAll(new[] { leftTask, rightTask });
await Calculate3();
return true;
}
Here I have some basic calculations (in Calculate1-Calculate3 procedures) of Calculations.cs file and some interaction with UI. The "entry point" Plot.UpdateData is placed in Device.StartTimer( block of the main form.
It works, but I think this structure creates excess threads. So my question is can this hierarhy be optimized without loss of asynchronous advantages?
Or, other words, which procedures should be awaited in case of nested calls. Where is first non-awaited call should lie? Thanks.
First thing to note: async/await is about tasks, not threads. Under certain circumstances, a task can be thread equivalent, and in most cases it is not (the same thread can serve a lot of tasks sequentially conveyor-style, depending on how they're scheduled for continuation and what is awaiting condition, for example).
And I could strongly recommend to address this for further reading as very comprehensive source:
https://blog.stephencleary.com/2013/11/there-is-no-thread.html
https://blog.stephencleary.com/2014/05/a-tour-of-task-part-1-constructors.html
I'm still getting up to speed with async & multi threading. I'm trying to monitor when the Task I Start is still running (to show in a UI). However it's indicating that it is RanToCompletion earlier than I want, when it hits an await, even when I consider its Status as still Running.
Here is the sample I'm doing. It all seems to be centred around the await's. When it hits an await, it is then marked as RanToCompletion.
I want to keep track of the main Task which starts it all, in a way which indicates to me that it is still running all the way to the end and only RanToCompletion when it is all done, including the repo call and the WhenAll.
How can I change this to get the feedback I want about the tskProdSeeding task status?
My Console application Main method calls this:
Task tskProdSeeding;
tskProdSeeding = Task.Factory.StartNew(SeedingProd, _cts.Token);
Which the runs this:
private async void SeedingProd(object state)
{
var token = (CancellationToken)state;
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
await Task.WhenAll(Task.Run(async () =>
{
foreach (var code in codesToSeed)
{
if (!token.IsCancellationRequested)
{
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
}
}, token));
Thread.Sleep(30000);
}
}
If you use async void the outer task can't tell when the task is finished, you need to use async Task instead.
Second, once you do switch to async Task, Task.Factory.StartNew can't handle functions that return a Task, you need to switch to Task.Run(
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
Once you do both of those changes you will be able to await or do a .Wait() on tskProdSeeding and it will properly wait till all the work is done before continuing.
Please read "Async/Await - Best Practices in Asynchronous Programming" to learn more about not doing async void.
Please read "StartNew is Dangerous" to learn more about why you should not be using StartNew the way you are using it.
P.S. In SeedingProd you should switch it to use await Task.Delay(30000); insetad of Thread.Sleep(30000);, you will then not tie up a thread while it waits. If you do this you likely could drop the
tskProdSeeding = Task.Run(() => SeedingProd(_cts.Token), _cts.Token);
and just make it
tskProdSeeding = SeedingProd(_cts.Token);
because the function no-longer has a blocking call inside of it.
I'm not convinced that you need a second thread (Task.Run or StartNew) at all. It looks like the bulk of the work is I/O-bound and if you're doing it asynchronously and using Task.Delay instead of Thread.Sleep, then there is no thread consumed by those operations and your UI shouldn't freeze. The first thing anyone new to async needs to understand is that it's not the same thing as multithreading. The latter is all about consuming more threads, the former is all about consuming fewer. Focus on eliminating the blocking and you shouldn't need a second thread.
As others have noted, SeedingProd needs to return a Task, not void, so you can observe its completion. I believe your method can be reduced to this:
private async Task SeedingProd(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
int totalSeeded = 0;
var codesToSeed = await _myRepository.All().ToListAsync(token);
foreach (var code in codesToSeed)
{
if (token.IsCancellationRequested)
return;
try
{
int seedCountByCode = await _myManager.SeedDataFromLive(code);
totalSeeded += seedCountByCode;
}
catch (Exception ex)
{
_logger.InfoFormat(ex.ToString());
}
}
await Task.Dealy(30000);
}
}
Then simply call the method, without awaiting it, and you'll have your task.
Task mainTask = SeedingProd(token);
When you specify async on a method, it compiles into a state machine with a Task, so SeedingProd does not run synchronously, but acts as a Task even if returns void. So when you call Task.Factory.StartNew(SeedingProd) you start a task that kick off another task - that's why the first one finishes immediately before the second one. All you have to do is add the Task return parameter instead of void:
private async Task SeedingProdAsync(CancellationToken ct)
{
...
}
and call it as simply as this:
Task tskProdSeeding = SeedingProdAsync(_cts.Token);
I'm running a test that should be calling a method multiple times without waiting for its result. Here's my code:
private async Task HandleJob(string params) {
// do stuff that takes a minute
Thread.Sleep(10000);
return;
}
[TestMethod]
public async Task StartTest() {
HandleJob("one");
HandleJob("two");
}
When I set a break at HandleJob("two"), it only gets hit after one has been completed. How do I make them run asynchronously, so no waiting is done?
You haven't used await in the method at all. This means that the method will execute the lines synchronously. To actually yield back to the caller and let the remaining code run asynchronously, you need to use await, which will continue the method as a continuation on the targeted Task (as well as unboxing any exceptions and return values)
There are a couple of helper methods in Task to assist with this - my favorite is Task.Yield(), which will immediately return, thus an await Task.Yield() will spit out into a new thread and return all at once.
[TestMethod]
public async Task StartTest() {
await Task.Yield(); // await yields control, and Yield will ensure the rest of the method starts immediately
HandleJob("one");
HandleJob("two");
}
If you want the individual subtasks to execute all at once, conglomerate them using Task.WhenAll and Task.Run
[TestMethod]
public async Task StartTest() {
await Task.WhenAll(
Task.Run(() => HandleJob("one")),
Task.Run(() => HandleJob("two")));
}
Your asynchronous method HandleJob is not really async as Thread.Sleep blocks the current thread. Try using await Task.Delay instead. Note that params is a keyword and your original code won't compile. I've changed it to parameters.
private async Task HandleJob(string parameters) {
// do stuff that takes a minute
await Task.Delay(10000);
return;
}
In your start method you can return a single Task that gets completed when both methods are finished using Task.WhenAll as pointed out in one of the other answers. If you return the result rather than await it, then the caller of StartTest can determine whether he waits for the Task to complete or if he ignores it and it becomes a fire and forget situation. Because you are not using await StartTest will not need to be marked as async anymore.
[TestMethod]
public Task StartTest() {
return Task.WhenAll(HandleJob("one"), HandleJob("two"));
}
you need to await both the tasks:
private void HandleJob( params string[] value )
{
return;
}
[TestMethod]
public async Task StartTest()
{
var task1 = Task.Run( () => HandleJob( "one" ) );
var task2 = Task.Run( () => HandleJob( "two" ) );
await Task.WhenAll( task1 , task2 );
}