Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bruno-/fiber_scheduler
Ruby's missing Fiber Scheduler implementation.
https://github.com/bruno-/fiber_scheduler
async async-programming asynchronous-programming concurrency fiber fiber-scheduler ruby
Last synced: 12 days ago
JSON representation
Ruby's missing Fiber Scheduler implementation.
- Host: GitHub
- URL: https://github.com/bruno-/fiber_scheduler
- Owner: bruno-
- License: mit
- Created: 2022-02-12T21:01:43.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2022-12-29T08:17:00.000Z (almost 2 years ago)
- Last Synced: 2024-10-14T16:55:15.342Z (24 days ago)
- Topics: async, async-programming, asynchronous-programming, concurrency, fiber, fiber-scheduler, ruby
- Language: Ruby
- Homepage:
- Size: 161 KB
- Stars: 119
- Watchers: 4
- Forks: 3
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Fiber Scheduler
Ruby 3 has
[Fiber Scheduler hooks](https://docs.ruby-lang.org/en/3.1/Fiber/SchedulerInterface.html)
that enable asynchronous programming. In order to make this work you need a
Fiber Scheduler implementation, **but Ruby does not provide a default one**.This gem aims to fill that void by providing a Fiber Scheduler class that makes
a great default. It's easy to use, performant, and can be used with
**just built-in Ruby methods**.`fiber_scheduler`'s killer feature 💣 is **full compatibility with any other
Fiber Scheduler implementation**, including the
[async gem](https://github.com/socketry/async). Write code using
`fiber_scheduler` and it works seamlessly with `async`, `bsync` or whatever
other `_sync` gem comes in the future.Learn more about the Ruby's
[Fiber Scheduler feature](https://brunosutic.com/blog/ruby-fiber-scheduler).### Installation
```
gem install fiber_scheduler
```Requires Ruby 3.1.
### Highlights
- Enables asynchronous (colorless) programming in Ruby.
- Killer feature: full compatibility with any other Fiber Scheduler
implementation, including the [async gem](https://github.com/socketry/async).
- Not a framework: no DSL or new APIs. Can be used with just built-in Ruby
methods:
[Fiber.set_scheduler](https://docs.ruby-lang.org/en/3.1/Fiber.html#method-c-set_scheduler)
and
[Fiber.schedule](https://docs.ruby-lang.org/en/3.1/Fiber.html#method-c-schedule).
- ~500 LOC of pure Ruby, no C extensions.
- No dependencies.### Setup
1. With a block (recommended)
2. Set `Fiber.scheduler` directly**With a block (recommended)**
```ruby
FiberScheduler do
# Your code here, e.g. Fiber.schedule { ... }
end
```Recommended because:
- This approach has
[full compatibility with any other Fiber Scheduler](https://github.com/bruno-/fiber_scheduler#compatibility-with-other-fiber-schedulers).
- `Fiber.scheduler` is automatically un-set outside the block.**Set Fiber.scheduler directly**
```ruby
Fiber.set_scheduler(FiberScheduler.new)# Your code here, e.g. Fiber.schedule { ... }
````Fiber.scheduler` is set until the end of the current thread, unless manually
unset with `Fiber.set_scheduler(nil)`.Pros:
- Uses only built-in Ruby methods `Fiber.set_scheduler` and `Fiber.schedule`.
Cons:
- No compatibility with other fiber schedulers.
### Examples
#### Basic example
This example runs two HTTP requests in parallel:
```ruby
require "fiber_scheduler"
require "open-uri"FiberScheduler do
Fiber.schedule do
URI.open("https://httpbin.org/delay/2")
endFiber.schedule do
URI.open("https://httpbin.org/delay/2")
end
end
```#### Advanced example
This example runs various operations in parallel. The example total running
time is slightly more than 2 seconds, which indicates all the operations ran in
parallel.Note that all the operations used in `Fiber.schedule` blocks below are either
common gems or built-in Ruby methods. They all work asynchronously with this
library, no monkey patching!```ruby
require "fiber_scheduler"
require "httparty"
require "open-uri"
require "redis"
require "sequel"DB = Sequel.postgres
Sequel.extension(:fiber_concurrency)FiberScheduler do
Fiber.schedule do
# This HTTP request takes 2 seconds (slightly more because of the latency)
URI.open("https://httpbin.org/delay/2")
endFiber.schedule do
# Use any HTTP library
HTTParty.get("https://httpbin.org/delay/2")
endFiber.schedule do
# Works with any TCP protocol library
Redis.new.blpop("abc123", 2)
endFiber.schedule do
# Make database queries
DB.run("SELECT pg_sleep(2)")
endFiber.schedule do
sleep 2
endFiber.schedule do
# Run system commands
`sleep 2`
end
end
```#### Scaling example
Easily run thousands and thousands of blocking operations in parallel. This
program finishes in about 2.5 seconds.```ruby
require "fiber_scheduler"FiberScheduler do
10_000.times do
Fiber.schedule do
sleep 2
end
end
end
```Gotcha: be careful about the overheads when scaling things. The below snippet
runs `sleep` which is an "inexpensive" operation. But, if we were to run
thousands of network requests there would be more overhead (establishing
TCP connections, SSL handshakes etc) which would prolong program running time.#### Nested Fiber.schedule example
It's possible to nest `Fiber.schedule` blocks arbitrarily deep.
All the `sleep` operations in this snippet run in parallel and the program
finishes in 2 seconds total.```ruby
require "fiber_scheduler"FiberScheduler do
Fiber.schedule do
Fiber.schedule do
sleep 2
endFiber.schedule do
sleep 2
endsleep 2
endFiber.schedule do
sleep 2
end
end
```#### Waiting Fiber.schedule example
Sometimes it's conventient for the parent to wait on the child fiber to
complete. Use `Fiber.schedule(:waiting)` to achieve that.In the below example fiber labeled `parent` will wait for the `child` fiber to
complete. Note that only the `parent` fiber waits, other fibers run as usual.This example takes 4 seconds to finish.
```ruby
require "fiber_scheduler"FiberScheduler do
Fiber.schedule do # parent
Fiber.schedule(:waiting) do # child
sleep 2
end
# The fiber stops here until the waiting child fiber completes.sleep 2
endFiber.schedule do
sleep 2
end
end
```#### Blocking Fiber.schedule example
Blocking fibers "block" all the other fibers from running until they're
finished.This example takes 4 seconds to finish.
```ruby
require "fiber_scheduler"FiberScheduler do
Fiber.schedule do
Fiber.schedule(:blocking) do
sleep 2
end
endFiber.schedule do
sleep 2
end
end
```#### Volatile Fiber.schedule example
Volatile fibers end when all the "durable" fibers finish.
Volatile fibers (by design) may not complete all their work.This is useful if you have a neverending task that performs some
cleanup work that should finish when the rest of the program completes.This example takes 2 seconds to finish.
```ruby
require "fiber_scheduler"FiberScheduler do
Fiber.schedule(:volatile) do
# This fiber will live for only 2 seconds.loop do
cleanup_work # this method will run only oncesleep 10
end
endFiber.schedule do
sleep 2
end
end
```### Compatibility with other fiber schedulers
#### [async gem](https://github.com/socketry/async)
`async` is an awesome asynchronous programming library, if not a framework.
If `async` is like Rails, then `fiber_scheduler` is plain Ruby.`fiber_scheduler` is fully compatible with `async`:
```ruby
Async do |task|
task.async do
# code ...
endFiberScheduler do
Fiber.schedule do
# code ...
end
end# ...
end
```Note that currently the opposite doesn't work:
```ruby
FiberScheduler do
Async do
# ...
endFiber.schedule do # No scheduler is available! (RuntimeError)
# ...
end
end
```#### Other Fiber Scheduler implementations
`fiber_scheduler` gem works with any other Fiber Scheduler class (current and
future ones). Example:```ruby
Fiber.set_scheduler(AnotherScheduler.new)# stuff
FiberScheduler do
# works just fine
end# more stuff
````fiber_scheduler` is like choosing pure Ruby: it's a safe choice because you
know it works and will continue working with everything else in Ruby's
asynchronous eco-system.### Performance
This [basic perf benchmark](examples/performance.rb) looks promising.
HINT: make sure to install `io-event` gem alongside `fiber_scheduler` for a
performance improvement.### Credits
Samuel Williams for:
- Implementing Ruby's Fiber Scheduler hooks.
- The [default selector](lib/fiber_scheduler/selector.rb) used in this gem.### License
[MIT](LICENSE)