{"id":16660672,"url":"https://github.com/ifesdjeen/hashed-wheel-timer","last_synced_at":"2025-07-10T12:34:04.601Z","repository":{"id":57720217,"uuid":"51778121","full_name":"ifesdjeen/hashed-wheel-timer","owner":"ifesdjeen","description":"High Performance Timer / Scheduler Library compatible with ScheduledExecutorService","archived":false,"fork":false,"pushed_at":"2017-08-23T01:34:25.000Z","size":167,"stargazers_count":225,"open_issues_count":2,"forks_count":44,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-12T15:56:58.565Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ifesdjeen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-15T19:01:00.000Z","updated_at":"2025-04-12T03:55:24.000Z","dependencies_parsed_at":"2022-09-26T21:41:19.805Z","dependency_job_id":null,"html_url":"https://github.com/ifesdjeen/hashed-wheel-timer","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ifesdjeen/hashed-wheel-timer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ifesdjeen%2Fhashed-wheel-timer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ifesdjeen%2Fhashed-wheel-timer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ifesdjeen%2Fhashed-wheel-timer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ifesdjeen%2Fhashed-wheel-timer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ifesdjeen","download_url":"https://codeload.github.com/ifesdjeen/hashed-wheel-timer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ifesdjeen%2Fhashed-wheel-timer/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264578900,"owners_count":23631555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T10:30:21.984Z","updated_at":"2025-07-10T12:34:04.325Z","avatar_url":"https://github.com/ifesdjeen.png","language":"Java","funding_links":[],"categories":["任务调度"],"sub_categories":[],"readme":"# What is the Hashed Timer?\n\nHashed and Hierarchical Wheels were used as a base for Kernels and Network stacks, and\nwere described by the [freebsd](http://people.freebsd.org/~davide/asia/callout_paper.pdf),\n[linux people](http://lwn.net/Articles/156329/),\n[researchers](http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf) and\nin many other searches.\n\nMany modern Java frameworks have their own implementations of Timing Wheels, for example,\n[Netty](https://github.com/netty/netty/blob/4.1/common/src/main/java/io/netty/util/HashedWheelTimer.java),\n[Agrona](https://github.com/real-logic/Agrona/blob/master/src/main/java/uk/co/real_logic/agrona/TimerWheel.java),\n[Reactor](https://github.com/reactor/reactor-core/blob/master/src/main/java/reactor/core/timer/HashWheelTimer.java),\n[Kafka](https://github.com/apache/kafka/blob/trunk/core/src/main/scala/kafka/utils/timer/Timer.scala),\n[Seastar](https://github.com/scylladb/seastar/blob/master/core/timer-set.hh)\nand many others. Of course, every implementation is adapted for the needs of the particular\nframework.\n\nThe concept on the Timer Wheel is rather simple to understand: in order to keep\ntrack of events on given resolution, an array of linked lists (alternatively -\nsets or even arrays, YMMV) is preallocated. When event is scheduled, it's\naddress is found by dividing deadline time `t` by `resolution` and `wheel size`.\nThe registration is then assigned with `rounds` (how many times we should go\naround the wheel in order for the time period to be elapsed).\n\nFor each scheduled resolution, a __bucket__ is created. There are `wheel size`\nbuckets, each one of which is holding `Registrations`. Timer is going through\neach `bucket` from the first until the next one, and decrements `rounds` for\neach registration. As soon as registration's `rounds` is reaching 0, the timeout\nis triggered. After that it is either rescheduled (with same `offset` and amount\nof `rounds` as initially) or removed from timer.\n\nHashed Wheel is often called __approximated timer__, since it acts on the\ncertain resolution, which allows it's optimisations. All the tasks scheduled for\nthe timer period lower than the resolution or \"between\" resolution steps will be\nrounded to the \"ceiling\" (for example, given resolution 10 milliseconds, all the\ntasks for 5,6,7 etc milliseconds will first fire after 10, and 15, 16, 17 will\nfirst trigger after 20).\n\nIf you're a visual person, it might be useful for you to check out [these\nslides](http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt),\nwhich help to understand the concept underlying the Hashed Wheel Timer better.\n\nThe early variant of this implementation was contributed to Project Reactor back in [2014](https://github.com/reactor/reactor/commit/53c0dcfab40b91838694843729c85c2effe7272b),\nand now is extracted and adopted to be used as a standalone library with benchmarks,\n`debounce`, `throttle` implementations, `ScheduledExecutorService` impl and\nother bells and whistles.\n\nFor __buckets__, `ConcurrentHashSet` is used (this, however, does not have any\ninfluence on the cancellation performance, it is still `O(1)` as cancellation is\nhandled during bucket iteration). Switching to the array didn't bring change\nperformance / throughput at all (however, reduced the memory footprint). Array\nimplementation is however harder to get right, as one would have to allow\nmultiple strategies for growth and shrinking of the underlying array.\n\nAdvancement would be to implement a hierarchical wheels, which would be quite\nsimple on top of this library.\n\n# nanoTime\n\nInternally, this library is using `nanoTime`, since it's a system timer (exactly\nwhat the library needs) best used for measuring elapsed time, exactly as JDK\ndocumentation states. One of the places to read about `nanoTime` is\n[here](http://shipilev.net/blog/2014/nanotrusting-nanotime/).\n\n# Waiting Strategies\n\nTimer Wheel allows you to pick between the three wait strategies: `BusySpin`\n(most resource- consuming), although resulting into the best precision. Timer\nloop will never release control, and will spin forever waiting for new tasks.\n`Yielding` strategy is some kind of a compromise, which yields control after\nchecking whether the deadline was reached or no. `Sleeping` strategy is\ninjecting a `Thread.sleep()` until the deadline. Moving from \"system\" timer\nusually means you don't want to use `sleep` at all. Except maybe for testing.\n\n# Usage\n\nLibrary implements `ScheduledExecutorService`. The decision was made to\nimplement this interface instead of `Timer`, since what the library does has\nmore to do with scheduled executor service than.\n\n# `debounce` and `throttle`\n\nFor convenience, library also provides\n[debounce](http://rxmarbles.com/#debounce) and throttle for `Runnable`,\n`Consumer` and `BiConsumer`, which allow you to wrap any runnable or consumer\ninto their debounced or throttled version. You can find more information about\ndebouncing and throttling by following the links above.\n\n# Comparison with JDK ScheduledExecutorService\n\nJDK Timers are great for the majority of cases. Benchmarks show that they're\nworking stably for \"reasonable\" amounts of events (tens of thousands).\n\nThe following charts show the performance of JDK `ScheduledExecutorService`\n(violet) vs `HashedWheelTimer` (black). The X is the amount of tasks submitted\nsequentially, the Y `Score` axis is the latency until all the tasks were executed.\n\n![Single Timer Benchmark](https://raw.githubusercontent.com/ifesdjeen/hashed-wheel-timer/master/doc/images/single_timer.png)\n\nIn the following chart, the Y axis is amount of tasks submitted sequentially,\nalthough from 10 threads, where each next thread is starting with 10 millisecond\ndelay.\n\n![Multi Timer Benchmark](https://raw.githubusercontent.com/ifesdjeen/hashed-wheel-timer/master/doc/images/multi_timer.png)\n\nIn both cases, 8 threads are used for workers. Changing amount of threads, hash\nwheel size, adding more events to benchmarks doesn't significantly change the\npicture.\n\nYou can see that `HashedWheelTimer` generally gives a flatter curve, which means\nthat given many fired events, it's precision is going to be better.\n\nAll benchmarks can be found\n[here](https://github.com/ifesdjeen/hashed-wheel-timer/tree/master/bench). If\nyou think the benchmarks are suboptimal, incomplete, unrealistic or biased, just\nfire an issue. It's always good to learn something new.\n\n## Artifact\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.github.ifesdjeen\u003c/groupId\u003e\n  \u003cartifactId\u003ehashed-wheel-timer-core\u003c/artifactId\u003e\n  \u003cversion\u003e1.0.0-RC1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nArtifact is hosted on Sonatype OSS repository:\n\n```xml\n\u003cdistributionManagement\u003e\n    \u003crepository\u003e\n      \u003cid\u003esonatype-releases\u003c/id\u003e\n      \u003cname\u003eSonatype Releases\u003c/name\u003e\n      \u003curl\u003ehttps://oss.sonatype.org/content/repositories/releases\u003c/url\u003e\n    \u003c/repository\u003e\n    \u003csnapshotRepository\u003e\n      \u003cid\u003esonatype-snapshots\u003c/id\u003e\n      \u003cname\u003eSonatype Snapshot\u003c/name\u003e\n      \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n    \u003c/snapshotRepository\u003e\n  \u003c/distributionManagement\u003e\n```\n\n## License\n\nCopyright © 2016 Alex P\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fifesdjeen%2Fhashed-wheel-timer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fifesdjeen%2Fhashed-wheel-timer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fifesdjeen%2Fhashed-wheel-timer/lists"}