I need to publish some data to the service from the C# web application. The data itself is collected when user uses the application (a kind of usage statistics). I don't want to send data to the service during each user's request, I would rather collect the data in the app and send then all the data in a single request in a separate thread, that does not serve the users requests (I mean user does not have to wait for the request to be processed by the service). For this purpose I need a kind of JS's setInterval analog - the launch of the function each X seconds to flush all collected data to the service.
I found out that Timer class provides somewhat similar (Elapsed event). However, this allows to run the method only once, but that's not a big issue. The main difficulty with it is that it requires the signature
void MethodName(object e, ElapsedEventArgs args)
while I would like to launch the async method, that will call the web-service (input parameters are not important):
async Task MethodName(object e, ElapsedEventArgs args)
Could anyone advise how to solve the described task? Any tips appreciated.
The async equivalent is a while loop with Task.Delay (which internally uses a System.Threading.Timer):
public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
await FooAsync();
await Task.Delay(interval, cancellationToken)
}
}
It's important to pass a CancellationToken so you can stop that operation when you want (e.g. when you shut down your application).
Now, while this is relevant for .Net in general, in ASP.Net it's dangerous to do any kind of fire and forget. There are several solution for this (like HangFire), some are documented in Fire and Forget on ASP.NET by Stephen Cleary others in How to run Background Tasks in ASP.NET by Scott Hanselman
Here is a method that invokes an asynchronous method in periodic fashion:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
while (true)
{
var delayTask = Task.Delay(interval, cancellationToken);
await action();
await delayTask;
}
}
The supplied action is invoked every interval, and then the created Task is awaited. The duration of the awaiting does not affect the interval, unless it happens to be longer than that. In that case the principle of no-overlapping-execution takes precedence, and so the period will be extended to match the duration of the awaiting.
In case of exception the PeriodicAsync task will complete with failure, so if you want it to be error-resilient you should include rigorous error handling inside the action.
Usage example:
Task statisticsUploader = PeriodicAsync(async () =>
{
try
{
await UploadStatisticsAsync();
}
catch (Exception ex)
{
// Log the exception
}
}, TimeSpan.FromMinutes(5));
.NET 6 update: It is now possible to implement an almost identical functionality without incurring the cost of a Task.Delay allocation on each loop, by using the new PeriodicTimer class:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
using var timer = new PeriodicTimer(interval);
while (true)
{
await action();
await timer.WaitForNextTickAsync(cancellationToken);
}
}
The WaitForNextTickAsync method returns a ValueTask<bool>, which is what makes this implementation more efficient. The difference in efficiency is pretty minuscule though. For a periodic action that runs every 5 minutes, allocating a few lightweight objects on each iteration should have practically zero impact.
The behavior of the PeriodicTimer-based implementation is not identical with the Task.Delay-based implementation. In case the duration of an action is longer than interval, both implementations will invoke the next action immediately after the completion of the previous action, but the scheduler of the PeriodicTimer-based implementation will not slide forward like the Task.Delay-based implementation does. See the marble diagram below for a visual demonstration of the difference:
Clock X---------X---------X---------X---------X---------X---------X--
Task.Delay: +-----| +---| +------------|+---| +------| +--|
PeriodicTimer: +-----| +---| +------------|+---| +------| +--| +--
The scheduling of the Task.Delay-based implementation was permanently shifted forward, because the third invocation of the action lasted longer than the interval.
The simple way of doing this is using Tasks and a simple loop:
public async Task StartTimer(CancellationToken cancellationToken)
{
await Task.Run(async () =>
{
while (true)
{
DoSomething();
await Task.Delay(10000, cancellationToken);
if (cancellationToken.IsCancellationRequested)
break;
}
});
}
When you want to stop the thread just abort the token:
cancellationToken.Cancel();
Related
I have a problem with the cancellationTokenSource in C#
public class Building {
public CancellationTokenSource BuildTokenSource;
public void StartBuilt()
{
BuildTokenSource = new CancellationTokenSource();
buildingService.buildTask = Task.Run(async () =>
{
await clock.Delay(BUILT_TIME);
}, BuildTokenSource.Token);
}
public void CancelBuilt()
{
if (BuildTokenSource != null)
{
BuildTokenSource.Cancel();
}
}
}
In another class in want to detect if the task is cancel like this but it doesn't work. The catch exception in never triggered
public async Task<Building> GetBuildingOfUserTask()
{
double remainingTime = unitService.GetRemainingTime();
if (remainingTime <= 2000 && remainingTime > 0.0)
{
Building building = GetBuilding();
CancellationToken cancellation = building.BuildTokenSource.Token;
try
{
await buildTask;
}
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
{
return GetBuildingOfUser();
}
}
return GetBuildingOfUser();
}
Anyone have any idea why this is not working and in this case a solution?
Does clock.Delay(BUILT_TIME) have an overload that accepts a CancellationToken? If so, use that.
The problem is if the code is already awaiting clock.Delay(BUILT_TIME) when you cancel, clock.Delay would not know that it needs throw an exception.
I don't see anywhere calling CancelBuilt() + you must call BuildTokenSource.Token.ThrowIfCancellationRequested() in order to raise OperationCanceledException exception
The token.Cancel() should be called outside the async method consuming the cancelationToken. Also consuming async method must call (usually in every step) Token.ThrowIfCancellationRequested();
Using a Mediator (Mediator design pattern) will be a better fit I believe. This is practically a pub-sub model that will publish an event on cancel and will inform all subscribers.
The first class will have the mediator instance as a reference (a read-only field, a property) to publish the cancel event and the other one should have the same instance as reference in order to be informed when the event actually takes place. Another point that you should take is the subscription that should be cancelled when the instance of the class that contains 'GetBuildingOfUserTask' method is destroyed.
What do you think?
I agree the answer of HadascokJ and I would like to bring more light.
You have a main task started at Task buildingService.buildTask and it subordinated one started at await clock.Delay(BUILT_TIME);
The first Task manages the CancellationToken but the subordinated one not. To figure it better replace your clock.Delay(BUILT_TIME) with a Task Task.Delay(int millisecondsDelay, CancellationToken cancellationToken); and provide, of course the CancelationToken. You will see that, in this case, the subordinated Task will be canceled. Also invoking void CancellationToken.CancelAfter(int millisecondsDelay)
As you do not provide the CancellationToken to the subordinated Task, ones the main Task has been started, neither the main nor its subordinated task will be canceled.
In the other hand, to cancel at execution of the subordinated Task, provide to the subordinated task some logic to manage the CancelationToken into its corresponding method and invoke the CancelationToken.ThrowIfCancellationRequested() whenever is necessary, which throws the OperationCanceledException.
At least, try to split long task into several small ones.
I use to manage async. Tasks, those have to be run sequentially into a Queue of task able to observe these TaskStatus. To deal with that, I have one implementation at github if you need. I call it FifoTaskQueue
Let's say I have an object with one method that is constantly running.
I already created a new thread running this method:
new Thread(new ThreadStart(myObject.firstMethod)).Start();
Now, I have a secondMethod in myObject that I want to start.
Keep in mind that the previously strarted thread isn't terminated because firstMethod contains a Loop.
How can I start the second method? Do I need to create a second Thread?
Its kind of unclear what you are asking or what you are exactly trying to achieve, however here is an example using Task running 2 endless loops (until a cancellation token is called)
public static void Method1(CancellationToken token)
{
Task.Run(
async () =>
{
while (!token.IsCancellationRequested)
{
// do something
await Task.Delay(500, token); // <- await with cancellation
Console.WriteLine("Method1");
}
}, token);
}
public static void Method2(CancellationToken token)
{
Task.Run(
async () =>
{
while (!token.IsCancellationRequested)
{
// do something
await Task.Delay(300, token); // <- await with cancellation
Console.WriteLine("Method2");
}
}, token);
}
private static void Main(string[] args)
{
var source = new CancellationTokenSource();
Method1(source.Token);
Method2(source.Token);
source.CancelAfter(3000);
Console.ReadKey();
}
Demo Here
Task vs Thread differences
Thread is a lower-level concept: if you're directly starting a
thread, you know it will be a separate thread, rather than executing
on the thread pool etc.
Task is more than just an abstraction of "where to run some code"
though - it's really just "the promise of a result in the future". So
as some different examples:
Task.Delay doesn't need any actual CPU time; it's just like setting a timer to go off in the future
A task returned by WebClient.DownloadStringTaskAsync won't take much CPU time locally; it's representing a result which is likely to
spend most of its time in network latency or remote work (at the web
server)
A task returned by Task.Run() really is saying "I want you to execute this code separately"; the exact thread on which that code
executes depends on a number of factors.
Note that the Task<T> abstraction is pivotal to the async support in
C# 5.
In general, I'd recommend that you use the higher level abstraction
wherever you can: in modern C# code you should rarely need to
explicitly start your own thread.
Quote Jon Skeet
What is the correct way to cancel the following?
var tcpListener = new TcpListener(connection);
tcpListener.Start();
var client = await tcpListener.AcceptTcpClientAsync();
Simply calling tcpListener.Stop() seems to result in an ObjectDisposedException and the AcceptTcpClientAsync method doesn't accept a CancellationToken structure.
Am I totally missing something obvious?
Assuming that you don't want to call the Stop method on the TcpListener class, there's no perfect solution here.
If you're alright with being notified when the operation doesn't complete within a certain time frame, but allowing the original operation to complete, then you can create an extension method, like so:
public static async Task<T> WithWaitCancellation<T>(
this Task<T> task, CancellationToken cancellationToken)
{
// The tasck completion source.
var tcs = new TaskCompletionSource<bool>();
// Register with the cancellation token.
using(cancellationToken.Register( s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs) )
{
// If the task waited on is the cancellation token...
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
}
// Wait for one or the other to complete.
return await task;
}
The above is from Stephen Toub's blog post "How do I cancel non-cancelable async operations?".
The caveat here bears repeating, this doesn't actually cancel the operation, because there is not an overload of the AcceptTcpClientAsync method that takes a CancellationToken, it's not able to be cancelled.
That means that if the extension method indicates that a cancellation did happen, you are cancelling the wait on the callback of the original Task, not cancelling the operation itself.
To that end, that is why I've renamed the method from WithCancellation to WithWaitCancellation to indicate that you are cancelling the wait, not the actual action.
From there, it's easy to use in your code:
// Create the listener.
var tcpListener = new TcpListener(connection);
// Start.
tcpListener.Start();
// The CancellationToken.
var cancellationToken = ...;
// Have to wait on an OperationCanceledException
// to see if it was cancelled.
try
{
// Wait for the client, with the ability to cancel
// the *wait*.
var client = await tcpListener.AcceptTcpClientAsync().
WithWaitCancellation(cancellationToken);
}
catch (AggregateException ae)
{
// Async exceptions are wrapped in
// an AggregateException, so you have to
// look here as well.
}
catch (OperationCancelledException oce)
{
// The operation was cancelled, branch
// code here.
}
Note that you'll have to wrap the call for your client to capture the OperationCanceledException instance thrown if the wait is cancelled.
I've also thrown in an AggregateException catch as exceptions are wrapped when thrown from asynchronous operations (you should test for yourself in this case).
That leaves the question of which approach is a better approach in the face of having a method like the Stop method (basically, anything which violently tears everything down, regardless of what is going on), which of course, depends on your circumstances.
If you are not sharing the resource that you're waiting on (in this case, the TcpListener), then it would probably be a better use of resources to call the abort method and swallow any exceptions that come from operations you're waiting on (you'll have to flip a bit when you call stop and monitor that bit in the other areas you're waiting on an operation). This adds some complexity to the code but if you're concerned about resource utilization and cleaning up as soon as possible, and this choice is available to you, then this is the way to go.
If resource utilization is not an issue and you're comfortable with a more cooperative mechanism, and you're not sharing the resource, then using the WithWaitCancellation method is fine. The pros here are that it's cleaner code, and easier to maintain.
While casperOne's answer is correct, there's a cleaner potential implementation to the WithCancellation (or WithWaitCancellation) extension method that achieves the same goals:
static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
First we have a fast-path optimization by checking whether the task has already completed.
Then we simply register a continuation to the original task and pass on the CancellationToken parameter.
The continuation extracts the original task's result (or exception if there is one) synchronously if possible (TaskContinuationOptions.ExecuteSynchronously) and using a ThreadPool thread if not (TaskScheduler.Default) while observing the CancellationToken for cancellation.
If the original task completes before the CancellationToken is canceled then the returned task stores the result, otherwise the task is canceled and will throw a TaskCancelledException when awaited.
The Task does not maintain a wait handle for performance reasons, and only lazily constructs one if the code were to ask one of it.
How then does a Task know it has been completed?
One would argue that the implementer sets the result on the TaskCompletionSource in their implementation but that would explain only the modern implementations and re-writes such as System.IO.FileStream.Begin/EndReadTask.
I followed the Task.IsComplete property; almost in every instance, an internal bitwise flag field (m_stateFlags) is set by the TrySetResult / TrySetException methods to indicate the status of the task.
But that does not cover all cases.
What about a method such as this?
public async Task FooAsync()
{
await Task.Run(() => { });
}
How then does a Task know it has been completed?
As I describe on my blog (overview, more detail), there are two kinds of tasks: Delegate Tasks (which execute code) and Promise Tasks (which represent an event).
Delegate Tasks complete themselves when their delegate completes.
Promise Tasks are completed from an external signal, using TaskCompletionSource<T> (or equivalent methods that are internal to the BCL).
I am answering my own question because I have suddenly remembered that I know the answer to it.
When using the C# Language Support Features
It's the state machine.
If the implementer of the asynchronous method used the C# language support such as the async keyword in the method declaration and the await keyword inside the method body to await an operation intrinsic to the task, then to the extent of the task he is implementing, the state machine signals task completion by setting the result of the task.
For e.g. if his implementation was as such:
// client code
public async void TopLevelMethod()
{
await MyMethodAsync();
}
// library code -- his implementation
public async Task MyMethodAsync()
{
await AnotherOperationAsync();
}
Then the completion of MyMethodAsync will be entrusted to the compiler generated state machine.
Of course, the signaling of completion of AnotherOperationAsync will also be taken care of by the compiler generated state machine, but that is not the point here.
Recall the states inside the MoveNext method indicate the task completion states and in the block inside of MoveNext that invokes the continuation callback, it also calls SetResult on the AsyncXXXMethodBuilder.
When not using the C# Language Support Features
If, however, the implementer of the asynchronous method did not make use of the C# language features, then it is the duty of the implementer to signal the completion of the task by setting the relevant result, exception or cancelled properties on the TaskCompletionSource object.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource<object>();
try
{
AnotherOperation();
tcs.SetResult();
}
catch(Exception ex)
{
tcs.SetException(ex);
}
return tcs.Task;
}
If the implementer did not use TPL support or invoked another operation asynchronously using the older .NET API, then too, it is the implementer's responsibility to signal task completion by explicitly setting the status of the task through one of the Try/SetResult/Exception etc. methods.
For e.g.
public Task MyMethodAsync()
{
var tcs = new TaskCompletionSource...
var autoReseEvent = ...
ThreadPool.QueueUserWorkItem(new WaitCallback(() =>
{
/* Work */
Thread.SpinWait(1000);
tcs.SetResult(...);
autoResetEvent.Set();
};)...;
return tcs.Task;
}
An Ill-Advised Case
The best way to await a task is, of course, to use the await keyword. If, however, when implementing an asynchronous API, the implementer does this:
public Task MyMethodAsync()
{
return Task.Run(...);
}
That would leave the consumer of his API with a sour mouth, I suppose?
Task.Run should only ever be used in a fire and forget scenario where you do not care about the point in time when the task will be completed.
The one exception to this is if you awaited the task returned by the call to Task.Run using the await keyword, like the code snippet shown below, in which case, you would be using the language support as described in the first section.
public async Task MyMethodAsync()
{
await Task.Run(...);
}
I need to publish some data to the service from the C# web application. The data itself is collected when user uses the application (a kind of usage statistics). I don't want to send data to the service during each user's request, I would rather collect the data in the app and send then all the data in a single request in a separate thread, that does not serve the users requests (I mean user does not have to wait for the request to be processed by the service). For this purpose I need a kind of JS's setInterval analog - the launch of the function each X seconds to flush all collected data to the service.
I found out that Timer class provides somewhat similar (Elapsed event). However, this allows to run the method only once, but that's not a big issue. The main difficulty with it is that it requires the signature
void MethodName(object e, ElapsedEventArgs args)
while I would like to launch the async method, that will call the web-service (input parameters are not important):
async Task MethodName(object e, ElapsedEventArgs args)
Could anyone advise how to solve the described task? Any tips appreciated.
The async equivalent is a while loop with Task.Delay (which internally uses a System.Threading.Timer):
public async Task PeriodicFooAsync(TimeSpan interval, CancellationToken cancellationToken)
{
while (true)
{
await FooAsync();
await Task.Delay(interval, cancellationToken)
}
}
It's important to pass a CancellationToken so you can stop that operation when you want (e.g. when you shut down your application).
Now, while this is relevant for .Net in general, in ASP.Net it's dangerous to do any kind of fire and forget. There are several solution for this (like HangFire), some are documented in Fire and Forget on ASP.NET by Stephen Cleary others in How to run Background Tasks in ASP.NET by Scott Hanselman
Here is a method that invokes an asynchronous method in periodic fashion:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
while (true)
{
var delayTask = Task.Delay(interval, cancellationToken);
await action();
await delayTask;
}
}
The supplied action is invoked every interval, and then the created Task is awaited. The duration of the awaiting does not affect the interval, unless it happens to be longer than that. In that case the principle of no-overlapping-execution takes precedence, and so the period will be extended to match the duration of the awaiting.
In case of exception the PeriodicAsync task will complete with failure, so if you want it to be error-resilient you should include rigorous error handling inside the action.
Usage example:
Task statisticsUploader = PeriodicAsync(async () =>
{
try
{
await UploadStatisticsAsync();
}
catch (Exception ex)
{
// Log the exception
}
}, TimeSpan.FromMinutes(5));
.NET 6 update: It is now possible to implement an almost identical functionality without incurring the cost of a Task.Delay allocation on each loop, by using the new PeriodicTimer class:
public static async Task PeriodicAsync(Func<Task> action, TimeSpan interval,
CancellationToken cancellationToken = default)
{
using var timer = new PeriodicTimer(interval);
while (true)
{
await action();
await timer.WaitForNextTickAsync(cancellationToken);
}
}
The WaitForNextTickAsync method returns a ValueTask<bool>, which is what makes this implementation more efficient. The difference in efficiency is pretty minuscule though. For a periodic action that runs every 5 minutes, allocating a few lightweight objects on each iteration should have practically zero impact.
The behavior of the PeriodicTimer-based implementation is not identical with the Task.Delay-based implementation. In case the duration of an action is longer than interval, both implementations will invoke the next action immediately after the completion of the previous action, but the scheduler of the PeriodicTimer-based implementation will not slide forward like the Task.Delay-based implementation does. See the marble diagram below for a visual demonstration of the difference:
Clock X---------X---------X---------X---------X---------X---------X--
Task.Delay: +-----| +---| +------------|+---| +------| +--|
PeriodicTimer: +-----| +---| +------------|+---| +------| +--| +--
The scheduling of the Task.Delay-based implementation was permanently shifted forward, because the third invocation of the action lasted longer than the interval.
The simple way of doing this is using Tasks and a simple loop:
public async Task StartTimer(CancellationToken cancellationToken)
{
await Task.Run(async () =>
{
while (true)
{
DoSomething();
await Task.Delay(10000, cancellationToken);
if (cancellationToken.IsCancellationRequested)
break;
}
});
}
When you want to stop the thread just abort the token:
cancellationToken.Cancel();