How to wait for multiple C# events? - c#

I would like find out a good solution for the following problem.
For example I have 5 timer what I start from 1 thread. These timers finish their work after few second (this is a retry mechanism). And I would like to wait to all of the timers finish their work.
So the question is that, Is there any good pattern which can handle this problem? Or do you now a good solution which is not a bool collection and if all of the elements are true then all of the timer finished :D
Thank you for your answer in advance!

This sounds like you really want to use Task instead of Timer.
Silly example:
async Task DoAsync()
{
var allTheWork = new [] { Work(), Work(), Work() };
await Task.WhenAll(allTheWork);
// Did all the sub-tasks return true?
if (allTheWork.All(i => i.Result))
{
}
}
async Task<bool> Work()
{
var retries = 3;
while (retries-- > 0)
{
if (success) return true;
await Task.Delay(2000); // This is the timer; you can find better retry patterns of course
}
return false;
}

There are multiple solutions to your problem.
I would suggest you take a look at Rx (Reactive Extensions) if you are familiar with linq since they use a very similar syntax. Rx allows you to do a lot of things with all sorts of events.
Another way is to use TPL (task parallel library) as follows:
var timer1 = Task.Delay(1000);
var timer2 = Task.Delay(2000);
var timer3 = Task.Delay(3000);
await Task.WhenAll(timer1, timer2, timer3);
Notice that you have to call this from an async context. If you are not familiar with async/await I recommend you take a look at it. If you don't want to / can't take a look at it you could simply do the following:
Task.WhenAll(timer1, timer2, timer3).GetAwaiter().GetResult();

Related

Call C# Task Repeatedly on conclusion

I have a C# app that must run blocks of code in parallel. Here is the basic structure of two of those blocks of code. In reality, there will be many more.
private async Task MyFirstTask()
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
Some of these blocks of code will run on a timer. Some will run repeatedly. In an attempt to accomplish, I have the following:
Task.Run(() => MyFirstTask());
Task.Run(() => MySecondTask());
When MyFirstTask has completed, I want to run it again. In fact, I want to run it over-and-over again until the program stops. Yet, I want MySecondTask to run in parallel of MyFirstTask. My question is, how do I execute MyFirstTask repeatedly, while still being parallel to MySecondTask?
I reviewed several of the related SO questions. I also do not see a Complete kind of event handler. So, I'm kind of lost in terms of how to implement this. I appreciate your help!
The beauty of async/await is that you can write asynchronous code in much the same way you'd write synchronous code. How would you repeat a synchronous operation? You could use a loop. You could do the same here, e.g.:
private async Task MyFirstTask(CancellationToken token) {
while (!token.IsCancellationRequested) {
// do stuff
await FirstTaskImplementation();
// cleanup
}
}
You can embed the loop in your current method or lift it into a wrapper method, but it should work either way.
You can continue scheduling your tasks the same way you're doing it now, though you really should await your async methods:
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(async () => await MyFirstTask(cts.Token));
Task.Run(async () => await MySecondTask());
// Request cancellation via `cts` when you want the looping to end.
And although you didn't ask about it, if you wanted to insert a delay between each iteration, you could simply place an await Task.Delay(...) statement at the end of the loop body.
You don't necessarily need to use Task.Run for the first task. You can use a Timer for the first task, with AutoReset set to true. That way it'll run forever and you don't have to worry about it anymore.
private static System.Timers.Timer aTimer;
public static void Main()
{
SetTimer(); //MyFirstTask starts running over and over in another thread
Task.Run(() => MySecondTask());
}
private static void SetTimer()
{
// Create a timer with a 1ms interval (has to be > 0)
aTimer = new System.Timers.Timer(1);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += MyFirstTask;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static async void MyFirstTask(Object source, ElapsedEventArgs e)
{
// do stuff
await FirstTaskImplementation();
// cleanup
}
private async Task MySecondTask()
{
// do stuff
await SecondTaskImplementation();
// cleanup
}
Another approach would be something like this:
var first=MyFirstTask().ToObservable();
var second=MySecondTask().ToObservable();
first.Repeat().Merge(second).Subscribe(x=>Console.WriteLine("Task completing."));
That's illustrative, not tested code. If you expect MySecondTask to complete, then perhaps this:
first.Repeat().TakeUntil(second).Subscribe(x=>Console.WriteLine("Task completing."));
If you want to add timeouts to second you could do this:
first.Repeat().TakeUntil(second.Timeout(TimeSpan.FromMilliseconds(100))).Subscribe(...)
If you want to show something on each task completion, declare the observables as:
var first=MyFirstTask().ToObservable().Do(Console.WriteLine("First completing"));
The above requires System.Reactive.Linq namespaces. I find these Rx based solutions to concurrency generally more elegant than the TPL, but that's just subjective.
Finally, if you do not want to start the tasks until the subscription is called, or something is ready to start watching, you can use Observable.FromAsync , as per info here

Task.ContinueWith seems to be called more often than there are actual tasks

First, this is from something much bigger and yes, I could completely avoid this using await under normal/other circumstances. For anyone interested, I'll explain below.
To track how many tasks I still have left before my program continues, I've built the following:
A counter:
private static int counter;
Some method:
public static void Test()
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10000; i++)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
var task = DoTaskWork();
task.ContinueWith(t => // After DoTaskWork
{
// [...] Use t's Result
counter--; // Decrease counter
tcs.SetResult(null); // Finish the task that the UI or whatever is waiting for
});
tasks.Add(tcs.Task); // Store tasks to wait for
}
Task.WaitAll(tasks.ToArray()); // Wait for all tasks that actually only finish in the ContinueWith
Console.WriteLine(counter);
}
My super heavy work to do:
private static Task DoTaskWork()
{
counter++; // Increase counter
return Task.Delay(500);
}
Now, interestingly I do not receive the number 0 at the end when looking at counter. Instead, the number varies with each execution. Why is this? I tried various tests, but cannot find the reason for the irregularity. With the TaskCompletionSource I believed this to be reliable. Thanks.
Now, for anyone that is interested in why I do this:
I need to create loads of tasks without starting them. For this I need to use the Task constructor (one of its rare use cases). Its disadvantage to Task.Run() is that it cannot handle anything with await and that it needs a return type from the Task to properly run (hence the null as result). Therefore, I need a way around that. Other ideas welcome...
Well. I am stupid. Just 5 minutes in, I realize that.
I just did the same while locking a helper object before changing the counter in any way and now it works...
private static int counter;
private static object locker = new object();
// [...]
task.ContinueWith(t =>
{
lock(locker)
counter--;
tcs.SetResult(null);
});
// [...]
private static Task DoTaskWork()
{
lock (locker)
counter++;
return Task.Delay(500);
}
I need to create loads of tasks without starting them ... Therefore, I need a way around that. Other ideas welcome...
So, if I read it correct you want to build a list of tasks without actually run them on creation. You could do that by building a list of Func<Task> objects you invoke when required:
async Task Main()
{
// Create list of work to do later
var tasks = new List<Func<Task>>();
// Schedule some work
tasks.Add(() => DoTaskWork(1));
tasks.Add(() => DoTaskWork(2));
// Wait for user input before doing work to demonstrate they are not started right away
Console.ReadLine();
// Execute and wait for the completion of the work to be done
await Task.WhenAll(tasks.Select(t => t.Invoke()));
Console.WriteLine("Ready");
}
public async Task DoTaskWork(int taskNr)
{
await Task.Delay(100);
Console.WriteLine(taskNr);
}
This will work, even if you use Task.Run like this:
public Task DoTaskWork(int taskNr)
{
return Task.Run(() =>
{
Thread.Sleep(100); Console.WriteLine(taskNr);
});
}
It this is not want you want can you elaborate more about the tasks you want to create?

Use Parallel.ForEach on method returning task - avoid Task.WaitAll

I've got a method which takes IWorkItem, starts work on it and returns related task. The method has to look like this because of external library used.
public Task WorkOn(IWorkItem workItem)
{
//...start asynchronous operation, return task
}
I want to do this work on multiple work items. I don't know how many of them will be there - maybe 1, maybe 10 000.
WorkOn method has internal pooling and may involve waiting if too many pararell executions will be reached. (like in SemaphoreSlim.Wait):
public Task WorkOn(IWorkItem workItem)
{
_semaphoreSlim.Wait();
}
My current solution is:
public void Do(params IWorkItem[] workItems)
{
var tasks = new Task[workItems.Length];
for (var i = 0; i < workItems.Length; i++)
{
tasks[i] = WorkOn(workItems[i]);
}
Task.WaitAll(tasks);
}
Question: may I use somehow Parallel.ForEach in this case? To avoid creating 10000 tasks and later wait because of WorkOn's throttling?
That actually is not that easy. You can use Parallel.ForEach to throttle the amount of tasks that are spawned. But I am unsure how that will perform/behave in your condition.
As a general rule of thumb I usually try to avoid mixing Task and Parallel.
Surely you can do something like this:
public void Do(params IWorkItem[] workItems)
{
Parallel.ForEach(workItems, (workItem) => WorkOn(workItem).Wait());
}
Under "normal" conditions this should limit your concurrency nicely.
You could also go full async-await and add some limiting to your concurrency with some tricks. But you have to do the concurrency limiting yourself in that case.
const int ConcurrencyLimit = 8;
public async Task Do(params IWorkItem[] workItems)
{
var cursor = 0;
var currentlyProcessing = new List<Task>(ConcurrencyLimit);
while (cursor < workItems.Length)
{
while (currentlyProcessing.Count < ConcurrencyLimit && cursor < workItems.Length)
{
currentlyProcessing.Add(WorkOn(workItems[cursor]));
cursor++;
}
Task finished = await Task.WhenAny(currentlyProcessing);
currentlyProcessing.Remove(finished);
}
await Task.WhenAll(currentlyProcessing);
}
As I said... a lot more complicated. But it will limit the concurrency to any value you apply as well. In addition it properly uses the async-await pattern. If you don't want non-blocking multi threading you can easily wrap this function into another function and do a blocking .Wait on the task returned by this function.
In key in this implementation is the Task.WhenAny function. This function will return one finished task in the applied list of task (wrapped by another task for the await.

What's the best implemention for non-blocking wait/delay for a period of time in c#

Currently I need to implement a simple non-blocking delay function in a Windows Store app project. This function should do nothing, just idle for a specific period of time without blocking the UI.
My question is: how to implement such a function properly? I know this is an old question, but I really have no clue after some search online.
Best wishes!
[Edit]
I've tried this but not work.
public static async Task WaitFor(int millisecondsDelay)
{
var idleTask = Task.Run(() => { Task.Delay(millisecondsDelay); });
await Task.WhenAny(new Task[] { idleTask });
}
See Task.Delay
It schedules a task that completes at a future time using timer rather than blocking a thread.
An example that waits 5 seconds and then continues:
private async Task DelayThenDoSomeWork()
{
await Task.Delay(5000);
// Do something
var dialog = new MessageDialog("Waiting completed.");
await dialog.ShowAsync();
}

Regarding the usage of SemaphoreSlim with Async/Await

I am not an advanced developer. I'm just trying to get a hold on the task library and just googling. I've never used the class SemaphoreSlim so I would like to know what it does. Here I present code where SemaphoreSlim is used with async & await but which I do not understand. Could someone help me to understand the code below.
1st set of code
await WorkerMainAsync();
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
while (true)
{
await ss.WaitAsync();
// you should probably store this task somewhere and then await it
var task = DoPollingThenWorkAsync();
}
}
async Task DoPollingThenWorkAsync(SemaphoreSlim semaphore)
{
var msg = Poll();
if (msg != null)
{
await Task.Delay(3000); // process the I/O-bound job
}
// this assumes you don't have to worry about exceptions
// otherwise consider try-finally
semaphore.Release();
}
Firstly, the WorkerMainAsync will be called and a SemaphoreSlim is used. Why is 10 passed to the constructor of SemaphoreSlim?
When does the control come out of the while loop again?
What does ss.WaitAsync(); do?
The DoPollingThenWorkAsync() function is expecting a SemaphoreSlim but is not passed anything when it is called. Is this typo?
Why is await Task.Delay(3000); used?
They could simply use Task.Delay(3000) but why do they use await here instead?
2nd set of code for same purpose
async Task WorkerMainAsync()
{
SemaphoreSlim ss = new SemaphoreSlim(10);
List<Task> trackedTasks = new List<Task>();
while (DoMore())
{
await ss.WaitAsync();
trackedTasks.Add(Task.Run(() =>
{
DoPollingThenWorkAsync();
ss.Release();
}));
}
await Task.WhenAll(trackedTasks);
}
void DoPollingThenWorkAsync()
{
var msg = Poll();
if (msg != null)
{
Thread.Sleep(2000); // process the long running CPU-bound job
}
}
Here is a task & ss.Release added to a list. I really do not understand how tasks can run after adding to a list?
trackedTasks.Add(Task.Run(async () =>
{
await DoPollingThenWorkAsync();
ss.Release();
}));
I am looking forward for a good explanation & help to understand the two sets of code. Thanks
why 10 is passing to SemaphoreSlim constructor.
They are using SemaphoreSlim to limit to 10 tasks at a time. The semaphore is "taken" before each task is started, and each task "releases" it when it finishes. For more about semaphores, see MSDN.
they can use simply Task.Delay(3000) but why they use await here.
Task.Delay creates a task that completes after the specified time interval and returns it. Like most Task-returning methods, Task.Delay returns immediately; it is the returned Task that has the delay. So if the code did not await it, there would be no delay.
just really do not understand after adding task to list how they can run?
In the Task-based Asynchronous Pattern, Task objects are returned "hot". This means they're already running by the time they're returned. The await Task.WhenAll at the end is waiting for them all to complete.

Categories