Nested await or async's "glutting" - c#

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

Related

SemaphoreSlim problems with async tasks

I've been attempting to use SemaphoreSlim to limit the amount of concurrent tasks I have running at any one time but it seems to have no effect, likely down to my implementation which is why I'm here. My SemaphoreSlim code is like so:
First it's called by
await Task.Run(() => mc.StartAsync());
Calling this method
public async Task StartAsync()
{
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
{
foreach (var task in ThreadHandler.ThreadList)
{
await concurrencySemaphore.WaitAsync();
try
{
await Task.Run(() => task.Operation.Start());
}
finally
{
concurrencySemaphore.Release();
}
}
}
}
This in turn is starting a task from a list which looks like this, this is in a custom model with the task stored and created previously
public Task Operation { get; set; }
var t = new Task(async () =>
{
await Task.Run(() => Method(input, sps));
});
Remembering my code doesn't work as I'd expect, is this the correct way to start something like this? I don't expect 3 tasks launching from a single point is a good idea. The main reason It's like this is because I'm executing an Action<> and couldn't figure out a way to await it alone. Do these tasks count towards the SemaphoreSlim limit?
After various tests I can confirm that my SemaphoreSlim code is just continuously executing the tasks, I added a large task delay into the list of tasks to see if I could stop it from executing which worked but new tasks were still launched... what am I missing?
My goal is to have a limit on the number of tasks concurrently running, if that wasn't clear. Thank you for any assistance!
EDIT: I think I've realised I'm only awaiting the starting of the task, not the completion.
I think I've realised I'm only awaiting the starting of the task, not the completion.
Indeed, that is the core of the problem.
You shouldn't use the Task constructor, ever, at all, for anything. Just pretend it doesn't exist. It will always lead you down an awkward path.
If you have an action you want to perform at a later time, you should use a delegate: Action or Func<T> for synchronous work, and Func<Task> or Func<Task<T>> for asynchronous work. E.g., if Method is synchronous, then you would have:
public Action Operation { get; set; }
...
Operation = () => Method(input, sps);
Then you can invoke it using Task.Run as such:
public async Task ProcessAsync()
{
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
{
var tasks = ThreadHandler.ThreadList.Select(async task =>
{
await concurrencySemaphore.WaitAsync();
try
{
await Task.Run(() => task.Operation());
}
finally
{
concurrencySemaphore.Release();
}
}).ToList();
await Task.WhenAll(tasks);
}
}
The above code will work fine if Operation is Action (synchronous) or Func<Task> (asynchronous).
However, if it is Action (i.e., synchronous), then what you're really doing is parallel processing, not asynchronous concurrency, and there's built-in types that can help with that:
public void Process()
{
// Only valid if Operation is Action, not Func<Task>!
Parallel.ForEach(
ThreadHandler.ThreadList,
new ParallelOptions { MaxDegreeOfParallelism = 5 },
task => task.Operation());
}

Queuing asynchronous task in C#

I have few methods that report some data to Data base. We want to invoke all calls to Data service asynchronously. These calls to data service are all over and so we want to make sure that these DS calls are executed one after another in order at any given time. Initially, i was using async await on each of these methods and each of the calls were executed asynchronously but we found out if they are out of sequence then there are room for errors.
So, i thought we should queue all these asynchronous tasks and send them in a separate thread but i want to know what options we have? I came across 'SemaphoreSlim' . Will this be appropriate in my use case?
Or what other options will suit my use case? Please, guide me.
So, what i have in my code currently
public static SemaphoreSlim mutex = new SemaphoreSlim(1);
//first DS call
public async Task SendModuleDataToDSAsync(Module parameters)
{
var tasks1 = new List<Task>();
var tasks2 = new List<Task>();
//await mutex.WaitAsync(); **//is this correct way to use SemaphoreSlim ?**
foreach (var setting in Module.param)
{
Task job1 = SaveModule(setting);
tasks1.Add(job1);
Task job2= SaveModule(GetAdvancedData(setting));
tasks2.Add(job2);
}
await Task.WhenAll(tasks1);
await Task.WhenAll(tasks2);
//mutex.Release(); // **is this correct?**
}
private async Task SaveModule(Module setting)
{
await Task.Run(() =>
{
// Invokes Calls to DS
...
});
}
//somewhere down the main thread, invoking second call to DS
//Second DS Call
private async Task SendInstrumentSettingsToDS(<param1>, <param2>)
{
//await mutex.WaitAsync();// **is this correct?**
await Task.Run(() =>
{
//TrackInstrumentInfoToDS
//mutex.Release();// **is this correct?**
});
if(param2)
{
await Task.Run(() =>
{
//TrackParam2InstrumentInfoToDS
});
}
}
Initially, i was using async await on each of these methods and each of the calls were executed asynchronously but we found out if they are out of sequence then there are room for errors.
So, i thought we should queue all these asynchronous tasks and send them in a separate thread but i want to know what options we have? I came across 'SemaphoreSlim' .
SemaphoreSlim does restrict asynchronous code to running one at a time, and is a valid form of mutual exclusion. However, since "out of sequence" calls can cause errors, then SemaphoreSlim is not an appropriate solution since it does not guarantee FIFO.
In a more general sense, no synchronization primitive guarantees FIFO because that can cause problems due to side effects like lock convoys. On the other hand, it is natural for data structures to be strictly FIFO.
So, you'll need to use your own FIFO queue, rather than having an implicit execution queue. Channels is a nice, performant, async-compatible queue, but since you're on an older version of C#/.NET, BlockingCollection<T> would work:
public sealed class ExecutionQueue
{
private readonly BlockingCollection<Func<Task>> _queue = new BlockingCollection<Func<Task>>();
public ExecutionQueue() => Completion = Task.Run(() => ProcessQueueAsync());
public Task Completion { get; }
public void Complete() => _queue.CompleteAdding();
private async Task ProcessQueueAsync()
{
foreach (var value in _queue.GetConsumingEnumerable())
await value();
}
}
The only tricky part with this setup is how to queue work. From the perspective of the code queueing the work, they want to know when the lambda is executed, not when the lambda is queued. From the perspective of the queue method (which I'm calling Run), the method needs to complete its returned task only after the lambda is executed. So, you can write the queue method something like this:
public Task Run(Func<Task> lambda)
{
var tcs = new TaskCompletionSource<object>();
_queue.Add(async () =>
{
// Execute the lambda and propagate the results to the Task returned from Run
try
{
await lambda();
tcs.TrySetResult(null);
}
catch (OperationCanceledException ex)
{
tcs.TrySetCanceled(ex.CancellationToken);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
This queueing method isn't as perfect as it could be. If a task completes with more than one exception (this is normal for parallel code), only the first one is retained (this is normal for async code). There's also an edge case around OperationCanceledException handling. But this code is good enough for most cases.
Now you can use it like this:
public static ExecutionQueue _queue = new ExecutionQueue();
public async Task SendModuleDataToDSAsync(Module parameters)
{
var tasks1 = new List<Task>();
var tasks2 = new List<Task>();
foreach (var setting in Module.param)
{
Task job1 = _queue.Run(() => SaveModule(setting));
tasks1.Add(job1);
Task job2 = _queue.Run(() => SaveModule(GetAdvancedData(setting)));
tasks2.Add(job2);
}
await Task.WhenAll(tasks1);
await Task.WhenAll(tasks2);
}
Here's a compact solution that has the least amount of moving parts but still guarantees FIFO ordering (unlike some of the suggested SemaphoreSlim solutions). There are two overloads for Enqueue so you can enqueue tasks with and without return values.
using System;
using System.Threading;
using System.Threading.Tasks;
public class TaskQueue
{
private Task _previousTask = Task.CompletedTask;
public Task Enqueue(Func<Task> asyncAction)
{
return Enqueue(async () => {
await asyncAction().ConfigureAwait(false);
return true;
});
}
public async Task<T> Enqueue<T>(Func<Task<T>> asyncFunction)
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
// get predecessor and wait until it's done. Also atomically swap in our own completion task.
await Interlocked.Exchange(ref _previousTask, tcs.Task).ConfigureAwait(false);
try
{
return await asyncFunction().ConfigureAwait(false);
}
finally
{
tcs.SetResult();
}
}
}
Please keep in mind that your first solution queueing all tasks to lists doesn't ensure that the tasks are executed one after another. They're all running in parallel because they're not awaited until the next tasks is startet.
So yes you've to use a SemapohoreSlim to use async locking and await. A simple implementation might be:
private readonly SemaphoreSlim _syncRoot = new SemaphoreSlim(1);
public async Task SendModuleDataToDSAsync(Module parameters)
{
await this._syncRoot.WaitAsync();
try
{
foreach (var setting in Module.param)
{
await SaveModule(setting);
await SaveModule(GetAdvancedData(setting));
}
}
finally
{
this._syncRoot.Release();
}
}
If you can use Nito.AsyncEx the code can be simplified to:
public async Task SendModuleDataToDSAsync(Module parameters)
{
using var lockHandle = await this._syncRoot.LockAsync();
foreach (var setting in Module.param)
{
await SaveModule(setting);
await SaveModule(GetAdvancedData(setting));
}
}
One option is to queue operations that will create tasks instead of queuing already running tasks as the code in the question does.
PseudoCode without locking:
Queue<Func<Task>> tasksQueue = new Queue<Func<Task>>();
async Task RunAllTasks()
{
while (tasksQueue.Count > 0)
{
var taskCreator = tasksQueue.Dequeu(); // get creator
var task = taskCreator(); // staring one task at a time here
await task; // wait till task completes
}
}
// note that declaring createSaveModuleTask does not
// start SaveModule task - it will only happen after this func is invoked
// inside RunAllTasks
Func<Task> createSaveModuleTask = () => SaveModule(setting);
tasksQueue.Add(createSaveModuleTask);
tasksQueue.Add(() => SaveModule(GetAdvancedData(setting)));
// no DB operations started at this point
// this will start tasks from the queue one by one.
await RunAllTasks();
Using ConcurrentQueue would be likely be right thing in actual code. You also would need to know total number of expected operations to stop when all are started and awaited one after another.
Building on your comment under Alexeis answer, your approch with the SemaphoreSlim is correct.
Assumeing that the methods SendInstrumentSettingsToDS and SendModuleDataToDSAsync are members of the same class. You simplay need a instance variable for a SemaphoreSlim and then at the start of each methode that needs synchornization call await lock.WaitAsync() and call lock.Release() in the finally block.
public async Task SendModuleDataToDSAsync(Module parameters)
{
await lock.WaitAsync();
try
{
...
}
finally
{
lock.Release();
}
}
private async Task SendInstrumentSettingsToDS(<param1>, <param2>)
{
await lock.WaitAsync();
try
{
...
}
finally
{
lock.Release();
}
}
and it is importend that the call to lock.Release() is in the finally-block, so that if an exception is thrown somewhere in the code of the try-block the semaphore is released.

not understanding of async await concept [duplicate]

This question already has an answer here:
Async Await Running Synchronously
(1 answer)
Closed 2 years ago.
I do not understand when I read the Microsoft documents about async and await working, as it says
Async methods are intended to be non-blocking operations. An await
expression in an async method doesn’t block the current thread while
the awaited task is running. Instead, the expression signs up the rest
of the method as a continuation and returns control to the caller of
the async method.
so consider my code:
public Form1()
{
InitializeComponent();
AsyncTest();
Test(1);
}
private async void AsyncTest()
{
HttpClient client = new HttpClient();
var ss = TT(2);
var s = await ss;
for (int i = 0; i < 10; i++)
{
//loop
}
}
private async Task<int> TT(int i)
{
while (true)
{
if (i > 1000000000)
break;
i++;
}
return i;
}
}
when ever I call AsyncTest(), it just waits behind TT method as it specified with await key, but what does it mean it return control to the main caller??
it is not been returned to the form1, if TT is an infinite loop it just remains forever.
thanks
It seems to me you are a newbee to async-await. You violate several rules about how to use async-await.
To make a function async do the following:
Declare the function async
Return Task<TResult> instead of TResult; return Task instead of void
ONLY EXCEPTION: event handlers return void instead of Task
there should be one await inside your async function. Your compiler will warn you if you omit this.
Make sure that all async functions that you call are awaited for before you return
Guideline: let async be a suffix to your async functions. This allows you to create a sync and an async function that do the same: void MyTest() and Task MyTestAsync()
Following these rules, you can't call an async function from within a constructor. As you are using Winforms your code could be like this:
public Form1()
{
InitializeComponent();
}
public async void OnButton1_Clicked(object sender, ...)
{ // because this is an event handler the return value is void
// Start the first test and await until ready
await TestAsync();
// Start the second test and await until ready:
int i = await TestAsync(1);
}
If you call an async function you know that somewhere inside this function is an await. If you have meaningful things to do while the inner function is awaiting, do not await yet. Do your useful things after the call and await the returned Task as soon as you need the result:
public async void OnButton2_Clicked(object sender, ...)
{
// Start a test, but don't await yet
var task1 = TestAsync(1);
// if here, function TestAsync is awaiting somewhere
// it is not finished yet, so you can't use the result of it
// But you can do Something else:
DoSomethingElse();
// if here you really need the result of TestAsync, await for it
int i = await task1;
// if here you know that TestAsync is finished, i has the proper return value
}
You don't have to start and await the tasks one by one, you can start several tasks and await for them as soon as you need the results:
public async void OnButton3_Clicked(object sender, ...)
{
// start several tasks. Don't await yet:
var task1 = TestAsync(1);
var task2 = TestAsync(2);
var task3 = TestAsync(3);
DoSomethingElse();
// if here I need the results of all three tasks:
var myTasks = new Task[] {task1, task2, task3};
await Task.WhenAll(myTasks);
}
An article that really helped me understanding async-await is this interview with Eric Lippert, where he compares async-await with a cook making breakfast. If a cook has to wait for the water to boil, he doesn't wait idly, but looks around to see if he can do other things. Search somewhere in the middle for async-await.
Another article that helped me following the guidelines of async-await is Async and Await by the ever so helpful Stephen Cleary

Async - Which of these is correct

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.

Dependencies between async tasks

I call my async method several times, ones for each unit
var tasks = otherData.Select(async unit =>
await OneUnitProcessor.ProcessOneUnitAsync(
var1,
authenticationResponse,
unit,
reservation: new Reservation()
)
);
await Task.WhenAll(tasks);
This is my async method:
public static async Task ProcessOneUnitAsync(string var1, ServiceResponse authenticationResponse, ChannelManagerJsonHolder unit,IReservation reservation, CookieCollection cookieCollection = null)
{
List<Task<HttpResponseMessage>> tasksDeleteReservations = reservation.DeleteReservations(allLinksToDelete, authenticationResponse, unit);
var occupiedPricesItems = OccupationPriceGetter.GetOccupiedPeriodsWithPrices(fiksniTecaj, authenticationResponse, unit, cookieCollection);
tasksOccupied = allOccupationsToInsert.Select(async price => await Api.CalendarPrices.SendRequestAsync(authenticationResponse, unit, price, unavailable: true));
await Task.WhenAll(tasksOccupied.Union(tasksDeleteReservations));
}
Basically there are tasks which delete reservations(tasksDeleteReservations) and tasks that insert reservations (tasksOccupied). This solution is not good for me because I want achieve solution that all "old" reservations are deleted before inserting new one (all tasksDeleteReservations tasks are finished before tasksOccupied)
One solution would be to have two awaits inside my async method, but I don't think it is good solution two have multiple awaits (control will return to the caller and I think program will exit before all other tasks (related to inserting reservations) are finished.
Other solution would be to block on deleting before contiuning to inserting, but this is probably not async code anymore.
How to achieve asynchronicity and order of execution in situation like this?
EDIT1: Here is the code that calls tasks which process all units;
private async Task ProcessAllUnits(string var1, IEnumerable<ChannelManagerJsonHolder> otherData, ServiceResponse authenticationResponse)
{
try
{
var tasks = otherData.Select(async unit => await OneUnitProcessor.ProcessOneUnitAsync(fiksniTecaj, authenticationResponse, unit, reservation: new Reservation()));
await Task.WhenAll(tasks);
}
catch (AggregateException ex)
{
foreach (var innerException in ex.InnerExceptions)
{
new FileLogger().Log("Unit level exception:" + innerException.Message, ChannelManager.Core.Utilities.Logging.LogLevel.Error);
}
}
}
ProcessAllUnits is called by some other method. Here is the code of that method:
private async Task LoginAndProcessAllUnits(string var1, UserModel oneGroupedCMJsonHolder,IAuthentication authentication)
{
var task = ProcessAllUnits(fiksniTecaj, otherData, authenticationResponse);
await task;
}
This is top level method:
public void ProcessAllUsersAsync(List<ChannelManagerJsonHolder> CMJsonHolder, string var1)
{
var tasks = new List<Task>();
foreach (var group in groupedCMJsonHolder)
{
var task = LoginAndProcessAllUnits(fiksniTecaj, group, new Authentication());
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
There's nothing wrong with having multiple awaits in one method. In fact, that's why you're using await in the first place, really - to manage the state machine and continuations for you.
Yes, control will return to the caller. But the point is, if you're using await, you need to use await all the way - the behaviour you're describing will only occur when your await chain is broken by some method that doesn't await on some asynchronous method. That's where your problem is, not the async methods that await multiple times.
All you need is two awaits on those task collections. Control does return to the caller but the task is not completed. If the task were completed by using await what good would the feature be?! It would amount to what return does.
The task that you start with async unit => ... will also complete only when then OneUnitProcessor.ProcessOneUnitAsync... task is done.
And await Task.WhenAll(tasks); completed when all these tasks are done.
await is for serializing execution of tasks.

Categories