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
Related
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();
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();
I have a situation (right or wrong) where I might need to abandon a running instance of a Task and start a new one. Cancellation is not an option as this is pretty much legacy code which would take a huge effort in building in support for passing cancellation tokens. I mean something like this
public Task TaskUnderObservation{get; private set;}
public async Task WatchTaskInternal(Func<Task<TResult>> task)
{
try
{
if (TaskUnderObservation != null) //basically if we are re-using this instance of class
ResetCommonTaskState();
TaskUnderObservation = task(); //Task is defined as a class level variable of type Task
LogManager.Instance.Info(this, "Started Task");
await Task;
}
catch (Exception ex)
{
LogManager.Instance.Error(this, "WatchTaskInternal Errored", ex);
}
}
The question is what happens to the running TaskUnderObservation is the method WatchTaskInternal is called repeatedly something like this.
var x = new TaskWatcherClass();
x.WatchTaskInternal (//some Func);
x.WatchTaskInternal (//some other FUNC);
Would my running task be abandoned or ignored? If I had a WPF application which was binding to the result of my TaskUnderObservation object would it bind it to the result of the first invocation or the most recent one?
You can't abandon running code. The running code must be complicit, and so support some kind of cancellation.
You can abandon the task by simply dropping the reference to it, but the code that is running will run to completion.
Don't be tempted to use Thread.Abort. It is pure evil.
I have following code which uses async await.
private async void DoAction()
{
foreach (var ele in new int[] { 1, 2, 3, 4, 5 })
{
int i = await LoadAction();
}
}
private Task<int> LoadAction()
{
Task<int> task = new Task<int>(CalledFromAsync);
return task;
}
private int CalledFromAsync()
{
Thread.Sleep(2000);
return rand.Next();
}
My CalledFromAsync() is never called. Am I doing anything wrong here? Please help me.
You are returning a task that never gets started. It is not a huge surprise that it never completes either. You need to use task.Start(); to start the task, or any of the other factory methods like Task.Run.
As mark said, using Task constructor returns a "cold task" in a "created" state, which hasn't started execution.
You should always use Task.Run or Task.Factory.Startnew when initiating a Task, which always return a "hot Task".
From the TAP Guidlines:
Task Status:
To support corner cases of types that derive from Task and Task<TResult>, and to support the separation of construction from scheduling, the Task class exposes a Start method. Tasks that are created by the public Task constructors are referred to as cold tasks, because they begin their life cycle in the non-scheduled Created state and are scheduled only when Start is called on these instances. All other tasks begin their life cycle in a hot state, which means that the asynchronous operations they represent have already been initiated and their task status is an enumeration value other than TaskStatus.Created. All tasks that are returned from TAP methods must be activated. If a TAP method internally uses a task’s constructor to instantiate the task to be returned, the TAP method must call Start on the Task object before returning it. Consumers of a TAP method may safely assume that the returned task is active and should not try to call Start on any Task that is returned from a TAP method. Calling Start on an active task results in an InvalidOperationException exception.