Skip to content

Scythemen/hashed-wheel-timer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hashed-wheel-timer

A .NET implementation of Timer, which optimized for approximated I/O timeout scheduling, also called Approximated Timer. Inspired by Netty HashedWheelTimer.

.NET implemented & Optimized & Notes:

  • Replace doubly-linked-list with singly-linked-list to reduce memory used.
  • Use ArrayPool to Prevent GC.
  • Optimized for small task that will be executed after a short delay. If it takes a long time to complete the task, consider to start a new thread.
  • tickDuration: the smaller value you set, the higher level of precision you get. but it will keep the timer busy for ticking. Adjust the tickDuration & ticksPerWheel in your case.
  • Testing passed of ~4,000,000 timer tasks, I think it's good enough for general scenarios.

Install

Download the source code, or NuGet package

https://www.nuget.org/packages/Cube.Timer

Usage

More details in the test-project

// constructor
public HashedWheelTimer(
    TimeSpan tickDuration,
    int ticksPerWheel = 512,
    long maxPendingTimerTasks = 0,
    ILogger<HashedWheelTimer> logger = null)
    

Create an instance of timer, then add new timer-task.

AddTask

var timer = new HashedWheelTimer(); // use the default value

// add a new task with lambda expression, delay 1357ms.
var handle = timer.AddTask(1357, () =>
{
    Debug.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} : do work. ");
});

// check the status of task
if(handle.Cancelled || handle.Expired) {  }

// task can be cancelled, call the method.
handle.Cancel();

// reuse the timerTask
timer.AddTask(2000, handle.TimerTask);

// ------------------
// add a new task with lambda expression, passing parameter=999
timer.AddTask(TimeSpan.FromMilliseconds(1234), (prm) =>
{
    Debug.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")} : do work. parameter={prm}");
}, 999);

// ------------------
// add a new task which instant class implements ITimerTask
timer.AddTask(4357, new MyTimerTask());
 
// ------------------
// stop the timer, and get the unprocessed tasks.
IEnumerable<TimerTaskHandle> unprocessedTasks = await timer.Stop(gatherUnprocessedTasks:true);

// ------------------
// check the padding tasks
if(timer.IsRunning && timer.PendingTasks != 0) { }

        

Implement the ITimerTask

public interface ITimerTask
{
    /// <summary>
    /// If it takes a long time to complete the task, consider to start a new thread. 
    /// </summary>
    /// <returns></returns>
    Task RunAsync();
}

public class MyTimerTask : ITimerTask
{
    public Task RunAsync()
    {
        Debug.WriteLine($"do work.");
        return Task.CompletedTask;
    }
}

AddNotice

For batch operation. A notice is an object, can represent anything.

// firstly set the callback delegate.
timer.SetNoticeCallback((notices) =>
{
    // batch operation
    foreach (var obj in notices)
    {
        // ... 
    }
});

// then add the notices.
timer.AddNotice(1357, 1357);
timer.AddNotice(TimeSpan.FromMilliseconds(1234), "{\"id\":32,\"name\":\"Jeo\"}");
// ... add more notices

About

A Timer optimized for approximated I/O timeout scheduling.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages