how to use async and await in timer - c#

My windows app's requirement are:
Using HttpWebRequest get web request/response every 3 seconds in one thread.(total is about 10 threads for doing this web request/response.)
Each thread use some global variables.
I want to use a System.Timers.Timer and async and await. But I don't know that is a best way for high performance. And then how to test them. I am a green in C#.

You could write a RepeatActionEvery() method as follows.
It's parameters are:
action - The action you want to repeat every so often.
interval - The delay interval between calling action().
cancellationToken - A token you use to cancel the loop.
Here's a compilable console application that demonstrates how you can call it. For an ASP application you would call it from an appropriate place.
Note that you need a way to cancel the loop, which is why I pass a CancellationToken to RepeatActionEvery(). In this sample, I use a cancellation source which automatically cancels after 8 seconds. You would probably have to provide a cancellation source for which some other code called .Cancel() at the appropriate time. See here for more details.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
sealed class Program
{
void run()
{
CancellationTokenSource cancellation = new CancellationTokenSource(
TimeSpan.FromSeconds(8));
Console.WriteLine("Starting action loop.");
RepeatActionEvery(() => Console.WriteLine("Action"),
TimeSpan.FromSeconds(1), cancellation.Token).Wait();
Console.WriteLine("Finished action loop.");
}
public static async Task RepeatActionEvery(Action action,
TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
action();
Task task = Task.Delay(interval, cancellationToken);
try
{
await task;
}
catch (TaskCanceledException)
{
return;
}
}
}
static void Main(string[] args)
{
new Program().run();
}
}
}

Related

How to store methods in a method that take methods as a parameters with action but using Task(Async)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
public class Task22 : MonoBehaviour
{
public event Action callback;
private Task allDone;
List<Task> allTasks = new List<Task>();
async void Start()
{
Task a = Task.Run(Looping1);
Task b = Task.Run(Looping2);
Task c = Task.Run(Looping3);
TaskDone(a,b,c);
}
async Task TaskDone(params Task\[\] tasks)
{
foreach (Task task in tasks)
{
allTasks.Add(task);
}
Task allTaskDone = Task.WhenAll(allTasks);
await allTaskDone;
Debug.Log("AllTaskDone");
}
async Task Looping1()
{
Debug.Log("StartTask1");
await Task.Delay(1000);
Debug.Log("Task1Done");
}
async Task Looping2()
{
Debug.Log("StartTask2");
await Task.Delay(2000);
Debug.Log("Task2Done");
}
async Task Looping3()
{
Debug.Log("StartTask3");
await Task.Delay(3000);
Debug.Log("Task3Done");
}
}
This is my output, although I don't understand why the output start with task 1 then 3 then 2. Since I add them with tasks a,b, and c, following the order of Task1 Task2, Task3 and code should run line by line. But that's just an additional question.
My main question is currently I can add the task into the "TaskDone" method, but all those tasks I need to declare first at the start and I want to skip this part. What I want to achieve is to create is to able to throw any task or method directly to a method that takes action as a parameter. The method doesn't know the number of tasks is thrown in but still able to handle it all.
Sorry if I am a bit unclear as I am a beginner and didn't find the answer I want on the internet
async Task TaskDoneAction(Action tasks//To store the task or throw method directly to here)
{
// Then I just do a for loop to see how many method or task is thrown here and add them to the list and do a callback when all tasks is done
Task allTaskDone = Task.WhenAll(allTasks);
await allTaskDone;
Debug.Log("AllTaskDone");
}
the order of starting tasks (that are meant to be started on the same time) are practically random (depends on so many thing and current state of the thread pool and task scheduler so it can be considered random), and you should not rely on it.
The method can have parameters of type Func. However you have to still start the task somewhere, but it can be done in the method itself, like:
async Task RunAll(params Func<Task>[] methods)
{
var tasks = methods.Select(m=>Task.Run(m)).ToList();
await Task.WhenAll(tasks);
}
async Task Main()
{
await RunAll(Looping1, Looping2, Looping3);
}

how to cancel a function after a while?

I want to know how can I cancel a function after a certain time!
for example, how can I cancel this function?
private async Task function()
{
try
{
while (true)
{
//mycode
}
}
catch{ }
}
how can I cancel this function?
Normally, awaitable methods will take a CancellationToken, so you'd just pass it on through:
private async Task functionAsync(CancellationToken cancellationToken)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); //mycode
}
}
Some time ago i faced the same issue and found a pretty good solution working for me. I am separating async calls to another service via wcf this way (see my code below) by doing two things to cancel after a maximum time:
You can use CancellationToken in combination with a second Task to run parallel to your running task and cancel it if necessary:
private const int TimeOut = 50000;
public static async Task<T> HandleServiceCall<T>(Func<Task<T>> doServiceCall, CancellationTokenSource source) where T : class
{
var delaySource = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
var res = doServiceCall();
if (await Task.WhenAny(res, Task.Delay(TimeSpan.FromMilliseconds(TimeOut), delaySource.Token)) == res)
{
delaySource.Cancel();
await res;
}
else
{
source.Cancel();
throw new Exception("Your Text");
}
return await res;
}
You can call this Method for example this way:
var source = new CancellationTokenSource(TimeSpan.FromSeconds(50));
source.Token.ThrowIfCancellationRequested();
MyWrapperClass.HandleServiceCall(async () => await MyAsyncMethod(source.Token), source).Result
To clarify what is done here:
I am creating a cancellation Token for my Task with a given max TimeSpan and then give this Token to the async Method which should be called.
This call is given as a func into my HandleServiceCall Method.
This Method will create another CancellationToken with a given greater TimeSpan, which will Run as a delayed Task (task.Delay will just wait until the Token is triggered).
Task.WhenAny will look if the normal async task or the delayed task is finishing first. If it is the delayed one, your maximum time has expired and an exception is thrown.
Greetings
Konstantin
You could use the Timer class, start it when you want it to (beginning of the program presumably), and use some like a simple if statement to stop it, such as *if timer is greater than set time, end program. *
I add small example
static CancellationTokenSource cts;
static void Main(string[] args)
{
cts = new CancellationTokenSource();
Task.Factory.StartNew(test);
cts.Cancel();
}
private async static void test()
{
await function(cts.Token);
}
static async Task function(CancellationToken ct)
{
try
{
while (!ct.IsCancellationRequested)
{
Thread.Sleep(1000);
//mycode
}
}
catch { }
}

C# .Net - How to make application wait until all threads created in Library are finished

I am trying to create a logging library and things are good until the application shutdown is called. When application shutdown is called, any unfinished thread is killed and the specific log is lost.
As of now application exits even before the first 10 threads are complete. I want help on how to make the application wait until all threads created by library are done.
NOTE:
Requirement I got are like this. Modifications should be only in the class 'Logging' since this will be a library and will be provided to end users. Handling of logging issues during app shutdown must be done within it. This is where I have trouble now.
Alternatively a solution like create an event in logging class to trigger all logging complete, and ask user to call app exit on that event is possible, but that I am trying to avoid since it adds that burden to end user and adds complexity for implementations. There is a possibility they may skip it, which I do not want. I am looking for a solution like user should do 'Logging.AddException(....)' and then forget about it.
Please help. Provide comments if you are not clear about the idea.
Here is the full code abstract which you can put into a console application.
Note: Look for comments in CASE 1 and CASE 2.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MultithreadKeepAlive
{
class Program
{
static void Main(string[] args)
{
LogLoadTest();
Logging.AddExceptionEntryAsync(new Exception("Last Exception"));
/*
* USE CASE 1: Enable the below lines and you will see how long it is supposed to take.
* Notice that currentDomain_ProcessExit will not trigger if below gets uncommented
*/
//Console.WriteLine("Main thread wait override");
//Console.ReadLine();
}
static void LogLoadTest()
{
//In real world this will be called from any place of application like startup or just after application shutdown is initiated.
//: NOTICE: Unlike the sample here, this will never be on loop and I am not looking for handling multithreads in this class.
// That responsibility I am planning to assign to Logging class.
// AND ALSO the class Logging is going to be in a seperate signed assembly where user of this class ('Program') should not worry about multithreads.
Task t;
for (int i = 0; i < 40; i++)
{
t = Logging.AddExceptionEntryAsync(new Exception("Hello Exception " + i), "Header info" + i);
}
}
}
public class Logging
{
static List<Task> tasks = new List<Task>();
static AppDomain currentDomain;
static Logging()
{
currentDomain = AppDomain.CurrentDomain;
currentDomain.ProcessExit += currentDomain_ProcessExit;
}
public static async Task AddExceptionEntryAsync(Exception ex, string header = "")
{
Task t = Task.Factory.StartNew(() => AddExceptionEntry(ex, header));
tasks.Add(t);
await t;
}
public static void AddExceptionEntry(Exception ex, string header)
{
/* Exception processing and write to file or DB. This might endup in file locks or
* network or any other cases where it will take delays from 1 sec to 5 minutes. */
Thread.Sleep(new Random().Next(1, 1000));
Console.WriteLine(ex.Message);
}
static void currentDomain_ProcessExit(object sender, EventArgs e)
{
Console.WriteLine("Application shutdown triggerd just now.");
Process.GetCurrentProcess().WaitForExit(); //1st attempt.
//Task.WaitAll(tasks.ToArray()); //2nd attempt
while (tasks.Any(t => !t.IsCompleted)) //3rd attempt.
{
}
/* USE CASE 2: IF WORKING GOOD, THIS WILL BE DISPLAYED IN CONSOLE AS LAST
* MESSAGE OF APPLICATION AND WILL WAIT FOR USER. THIS IS NOT WORKING NOW.*/
Console.WriteLine("All complete"); //this message should show up if this work properly
Console.ReadLine(); //for testing purpose wait for input from user after every thread is complete. Check all 40 threads are in console.
}
}
}
You can try
Task.WaitAll(tasks);
This waits for all of the provided Task objects to complete execution.
UPDATE : using async/await
With async and await, we formalize and clarify how asynchronous, non-blocking methods begin and end. An async method can return only void or a Task.
static void Main()
{
// Create task and start it.
// ... Wait for it to complete.
Task task = new Task(AsyncMethod);
task.Start();
task.Wait();
}
public static async void AsyncMethod(){
await AnotherMehod();}
static async Task AnotherMehod() { //TODO}
As of now I myself found a workaround.
/// <summary>
/// Makes the current thread Wait until any of the pending messages/Exceptions/Logs are completly written into respective sources.
/// Call this method before application is shutdown to make sure all logs are saved properly.
/// </summary>
public static void WaitForLogComplete()
{
Task.WaitAll(tasks.Values.ToArray());
}
Step 1: Consider changing to Task.Run() if you do not want the scheduler to be involved. I'm also assuming you want to wait until all async tasks finish.
public static AddExceptionEntry(Exception ex, string header = "")
{
Task t = Task.Factory.StartNew(() => AddExceptionEntry(ex, header));
tasks.Add(t);
WaitForExecutionAsync().ConfigureAwait(true);
}
public static async Task WaitForExecutionAsync()
{
if(tasks.Count >0)
await Task.WhenAll(tasks.ToArray());
// Raise Event.
}
To Block just call this to run sync vs async:
WaitForExecution().GetAwaiter().GetResult();

Pausing a task within Task.Factory.StartNew

In my Asp.Net MVC 5 project I have a ~3 minute task that I pass to Task.Factory.StartNew().
I would like to pause the task from within the task if there is a validation issue in one of the steps of my code running in the task. I don't want to delay it async because the rest of the task will continue to run, which can't happen.
Could I use thread.sleep() without any repercussions since I'm within a task? I read that I may have to use TaskScheduler.Default to have the Task.Factory create a new thread for each task.
I'm using a PauseToken similar to a CancellationToken so I'll be able to resume the task or cancel this task based on user input.
Multithreading really scares me, and I don't want to overlook something.
Here is an example of the Thread.Sleep implementation:
public void WaitIfPaused(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
{
//TODO: If paused for an hour notify user via noty and abort the task to keep it from completing by cancellation via cancellationToken.
//wait for 1 hour
for (int i = 0; i < 3600; i++)
{
ThrowExceptionIfCancelled(cancellationToken, progressBar);
if (pauseToken.IsPaused)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
}
PauseToken: http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx
Requested: Implementation of task structure in shared code library.
public void StartTask(params object[] data)
{
//throw an exception if no ITask was found
if (_taskToRun == null)
throw new Exception("Task cannot be null");
//set up task cancellation
CancellationTokenSource = new CancellationTokenSource();
var cancellationToken = CancellationTokenSource.Token;
//set up task pausing
PauseTokenSource = new PauseTokenSource();
var pauseToken = PauseTokenSource.Token;
//start a new task using the Task that was set
_task = Task.Factory.StartNew(() => _taskToRun.Execute(cancellationToken, pauseToken, data), cancellationToken);
}
My Execute method that is invoked by _taskToRun.Execute:
Public override void Execute(CancellationToken cancellationToken, PauseToken pauseToken, params object[] data)
{
var managerList = (List<IFileManager>) data[0];
var instr = (List<InstructionSet>) data[1];
ProcessInstructions(managerList, instr, cancellationToken, pauseToken);
}
Update due to comments:
Code example: 3 instructions
For(var instruction in instructions)
{
instruction.Execute();
}
In my execute method I run into a scenario for pause and call WaitWhilePausedAsync from within the execute. It will continue to execute the other two instructions, but pause the only the current instructions execute method.
Edit: By awaiting instruction.Execute() it will wait until instruction.Execute() completes or is unpaused.
Final Edit:
I was able to resolve the issue by awaiting the Execute method and making it async like Servy and I3arnon suggested.
Final Code Sample:
foreach(var instruction in instructions)
{
try
{
await instruction.Execute(pauseToken);
}
catch(InvalidOperationException)
{
pauseTokenSource.IsPaused = true;
//ask if user wants to cancel or resume.
}
}
//Simplified
public async Task<bool> Execute(PauseToken pauseToken)
{
await pauseToken.WaitWhilePausedAsync();
//do work
}
You can safely use Thread.Sleep. The only drawback is that the thread would be wasted blocking synchronously.
You should be using await Task.Delay(1000) instead. The code after that line would not execute until the wait is complete, but you won't be wasting a thread in the meantime:
public async Task WaitIfPausedAsync(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
{
for (int i = 0; i < 3600; i++)
{
ThrowExceptionIfCancelled(cancellationToken, progressBar);
if (pauseToken.IsPaused)
{
await Task.Delay(1000)
}
else
{
break;
}
}
}
Edit: I was unaware of PauseToken.WaitWhilePausedAsync. You should definitly use that instead of replicating that yourself with polling over PauseToken.IsPaused

How to start a Task using only the last trigger within x seconds?

I have a function that triggers a Task to start.
void function ()
{
new Task(async () =>
{
// await network operation
}).Start();
}
The function could get called many times very frequently. But I don't want the Task to be started each time, I want it to only start on the last trigger within let's say 5 seconds.
Here are the steps to what I want to do exactly
function() gets called
Have a delay for 5 seconds
if function() was called within those 5 seconds, I wish to cancel any pending Tasks, and start a delay of 5 seconds all over again
If function() was not called within those 5 seconds, I then wish to start the Task
Please guide me as how I would do that in C# .NET 4.5
The following code shows a simple Console Application that runs a task after 5 seconds and cancels the current task if a new one is started:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting");
Console.WriteLine("Press any key to call method or press Esc to cancel");
do
{
Method();
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
}
static Task delayTask = null;
static CancellationTokenSource cancellationTokenSource = null;
static void Method()
{
Console.WriteLine("Method called");
if (delayTask != null)
{
cancellationTokenSource.Cancel();
}
cancellationTokenSource = new CancellationTokenSource();
delayTask = Task.Delay(5000, cancellationTokenSource.Token);
delayTask.ContinueWith((t) => {
Console.WriteLine("Task running...");
}, TaskContinuationOptions.NotOnCanceled);
}
}
The code does not use async/await because those can't be used easily in a Console application (a Console Application doesn't have a SynchronizationContext). When using this code in a WinForms, WPF or ASP.NET application you can easily use async/await to improve upon the code. However, it does show the basic idea of using a CancellationTokenSource and combining a delay with another task.
A common term for this would be "debounce", and it's discussed here: C# event debounce

Categories

Resources