We have below class members for timer:
private Timer _activityTimer;
Instantiating this timer variable in one method:
_activityTimer =
new Timer(async (timerState) => await UpdateActivityAsync(_ipAddress), null, new Random().Next(1, 15000), 15000);
But this did not calling periodically when server has load.
It is showing below log in serilog:
To handle async periodic callback, I would use System.Threading.PeriodicTimer
. This way the execution of the next UpdateActivityAsync
will not begin until the last one is done. If you still face thread pool starvation issue, you could manually create an additional thread in which you run the timer.
class Example {
private PeriodicTimer _activityTimer;
private IPAddress _ipAddress = IPAddress.Parse("192.168.1.1");
public void StartTimer() {
// Starting the timer, but not awaiting to not block the calling thread
// If you still face thread pool starvation issue, you could manually create an additional thread here
StartTimerLoopAsync();
}
public void StopTimer() {
_activityTimer.Dispose();
}
private async Task StartTimerLoopAsync() {
_activityTimer = new PeriodicTimer(TimeSpan.FromMilliseconds(15000));
while (await _activityTimer.WaitForNextTickAsync()) {
await UpdateActivityAsync(_ipAddress);
}
}
private async Task UpdateActivityAsync(IPAddress ipAddress) {
await Task.Delay(500); // Simulate some IO
Console.WriteLine(ipAddress);
}
}
UPDATE for .NET Core 3.1
Instead of PeriodicTimer
you could simply use Task.Delay
(it's not very accurate, but good enough for your use case I believe):
class Example {
private CancellationTokenSource _cancellationTokenSource = new ();
private IPAddress _ipAddress = IPAddress.Parse("192.168.1.1");
public void StartTimer() {
// Starting the timer, but not awaiting to not block the calling thread
// If you still face thread pool starvation issue, you could manually create an additional thread here
StartTimerLoopAsync();
}
public void StopTimer() {
_cancellationTokenSource.Cancel();
}
private async Task StartTimerLoopAsync() {
await Task.Delay(new Random().Next(1, 15000)); // System.Threading.Timer first delay
while (!_cancellationTokenSource.IsCancellationRequested) {
// run the Delay and UpdateActivityAsync simultaneously and wait for both
var delayTask = Task.Delay(15000, _cancellationTokenSource.Token);
await UpdateActivityAsync(_ipAddress, _cancellationTokenSource.Token);
await delayTask;
}
}
private async Task UpdateActivityAsync(IPAddress ipAddress, CancellationToken cancellationToken) {
await Task.Delay(1500, cancellationToken); // Simulate some IO
Console.WriteLine(ipAddress);
}
}
UPDATE
You could also create your own async Timer:
class Example : IDisposable {
private AsyncTimer<Example>? _timer;
public IPAddress IpAddress = IPAddress.Parse("192.168.1.1");
public void StartTimer() {
if (_timer is not null) {
return;
}
_timer = new AsyncTimer<Example>(async (state, ct) => await UpdateActivityAsync(state.IpAddress, ct), this, new Random().Next(1, 15000), 15000);
}
public void StopTimer() {
_timer?.Stop();
}
private async Task UpdateActivityAsync(IPAddress ipAddress, CancellationToken cancellationToken) {
await Task.Delay(500, cancellationToken); // Simulate some IO
Console.WriteLine(ipAddress);
}
public void Dispose() {
_timer?.Dispose();
}
}
class AsyncTimer<T> : IDisposable {
public delegate Task AsyncTimerDelegate(T state, CancellationToken cancellationToken);
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly AsyncTimerDelegate _timerCallback;
private readonly TimeSpan _dueTime;
private readonly TimeSpan _interval;
private readonly T _state;
public AsyncTimer(AsyncTimerDelegate timerCallback, T state, int dueTime, int interval) {
_timerCallback = timerCallback;
_state = state;
_dueTime = TimeSpan.FromMilliseconds(dueTime);
_interval = TimeSpan.FromMilliseconds(interval);
// Starting the timer, but not awaiting to not block the calling thread
// If you still face thread pool starvation issue, you could manually create an additional thread here
StartTimerLoopAsync();
}
public void Stop() {
_cancellationTokenSource.Cancel();
}
private async Task StartTimerLoopAsync() {
await Task.Delay(_dueTime);
while (!_cancellationTokenSource.IsCancellationRequested) {
// run the Delay and UpdateActivityAsync simultaneously and wait for both
var delayTask = Task.Delay(_interval, _cancellationTokenSource.Token);
await _timerCallback.Invoke(_state, _cancellationTokenSource.Token);
await delayTask;
}
}
public void Dispose() {
_cancellationTokenSource.Dispose();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.