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.
Related
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());
}
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 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.
I have two services that ultimately both update the same object, so we have a test to ensure that the writes to that object complete (Under the hood we have retry policies on each).
9 times out of 10, one or more of the theories will fail, with the task.ShouldNotBeNull(); always being the assertion to fail. What am i getting wrong with the async code in this sample? Why would the task be null?
[Theory]
[InlineData(1)]
[InlineData(5)]
[InlineData(10)]
[InlineData(20)]
public async Task ConcurrencyIssueTest(int iterations)
{
var orderResult = await _driver.PlaceOrder();
var tasksA = new List<Task<ApiResponse<string>>>();
var tasksB = new List<Task<ApiResponse<string>>>();
await Task.Run(() => Parallel.For(1, iterations,
x =>
{
tasksA.Add(_Api.TaskA(orderResult.OrderId));
tasksB.Add(_Api.TaskB(orderResult.OrderId));
}));
//Check all tasks return successful
foreach (var task in tasksA)
{
task.ShouldNotBeNull();
var result = task.GetAwaiter().GetResult();
result.ShouldNotBeNull();
result.StatusCode.ShouldBe(HttpStatusCode.OK);
}
foreach (var task in tasksB)
{
task.ShouldNotBeNull();
var result = task.GetAwaiter().GetResult();
result.ShouldNotBeNull();
result.StatusCode.ShouldBe(HttpStatusCode.OK);
}
}
}
There's no need for Tasks and Parrallel looping here. I'm presuming that your _api calls are IO bound? You want something more like this:
var tasksA = new List<Task<ApiResponse<string>>>();
var tasksB = new List<Task<ApiResponse<string>>>();
//fire off all the async tasks
foreach(var it in iterations){
tasksA.Add(_Api.TaskA(orderResult.OrderId));
tasksB.Add(_Api.TaskB(orderResult.OrderId));
}
//await the results
await Task.WhenAll(tasksA).ConfigureAwait(false);
foreach (var task in tasksA)
{
//no need to get GetAwaiter(), you've awaited above.
task.Result;
}
//to get the most out of the async only await them just before you need them
await Task.WhenAll(tasksB).ConfigureAwait(false);
foreach (var task2 in tasksB)
{
task2.Result;
}
this will fire all your api calls async then block while the results return. You Parallel for and tasks are just using additional thread pool threads to zero benefit.
If _api is CPU bound you could get benefit from Task.Run but I'm guessing these are web api or something. So the Task.Run is doing nothing but using an additional thread.
As others have suggested, remove the Parallel, and await on all tasks to finish before asserting them.
I would also recommend to remove .Result from each task, and await them instead.
public async Task ConcurrencyIssueTest(int iterations)
{
var orderResult = await _driver.PlaceOrder();
var taskA = _Api.TaskA(orderResult.OrderId);
var taskB = _Api.TaskB(orderResult.OrderId);
await Task.WhenAll(taskA, taskB);
var taskAResult = await taskA;
taskAResult.ShouldNotBeNull();
taskAResult.StatusCode.ShouldBe(HttpStatusCode.OK);
var taskBResult = await taskB;
taskBResult.ShouldNotBeNull();
taskBResult.StatusCode.ShouldBe(HttpStatusCode.OK);
}
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