Skip to content

DedicatedThreadScheduler performance review #1593

@JeffCyr

Description

@JeffCyr

This issue is about analyzing the DedicatedThreadScheduler to discuss about how it could be improved.

https://github.com/akkadotnet/akka.net/blob/cf7cd6f274cd56af6403afc640a038564dc4d03b/src/core/Akka/Actor/Scheduler/DedicatedThreadScheduler.cs

Summary of the actual implementation

The scheduler is implemented by a background thread and a ConcurrentQueue. The ConcurrentQueue is used as a message queue to send the scheduled work items to the scheduler's background thread.

The background thread is a while loop that:

  • reads item from the message queue, add them in a List allWork
  • iterate all work items in allWork to invoke the expired items
  • sleep (defined by akka.scheduler.tick-duration)

Dedicated Thread vs Timer

If there are only a few instances of the scheduler, I think that the dedicated thread is the good approach. I don't see why you would need to have more than one in a process.

allWork data structure

The List is fairly inefficient since the scheduler has to iterate all work items every time. A heap structure should be a good match for this, it would be sorted by clock time and the scheduler would only have to check the head. The time complexity of the heap would be O(log n) for push and O(log n) for pop compared to O(1) for push and O(n) for pop for the List.

The optimal structure I can think of is a circular list of buckets with a resolution defined by tick-duration. The work items would be inserted in their appropriate bucket, push and pop to that structure would both be O(1). (To limit the size of the circular list, it should have one list with tick-duration resolution and another with a bigger resolution (e.g. 1 second))

Thread.Sleep vs Wake-up signals

With the current implementation, the thread wakes up every tick-duration to check if a work item expired. Depending on the work load, the scheduler could waste cpu cycles by waking up often when there is no expired work items.

Something like an AutoResetEvent could be used to wake up the thread only when it has actual work to do.

Execution of expired work items

With the current implementation, the work items are executed inside the scheduler's thread. This could potentially delay the execution of other work items. I think it should push the execution on the .Net ThreadPool and have an optional setting to execute a specific work item synchronously.

End note

Of course all this talk is theoretical, we should create a benchmark that mimics the expected work load in Akka.Net and try the various proposals.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions