README.md in polyphony-0.13 vs README.md in polyphony-0.14
- old
+ new
@@ -17,11 +17,11 @@
## What is Polyphony
Polyphony is a library for building concurrent applications in Ruby. Polyphony
harnesses the power of
[Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html) to provide a
-cooperative, sequential coroutine-based concurrency model. Under the hood,
+cooperative, sequential coprocess-based concurrency model. Under the hood,
Polyphony uses [libev](https://github.com/enki/libev) as a high-performance event
reactor that provides timers, I/O watchers and other asynchronous event
primitives.
Polyphony makes it possible to use normal Ruby built-in classes like `IO`, and
@@ -29,20 +29,22 @@
takes care of context-switching automatically whenever a blocking call like
`Socket#accept` or `IO#read` is issued.
## Features
+- **Full-blown, integrated, high-performance HTTP 1 / HTTP 2 / WebSocket server
+ with TLS/SSL termination and automatic ALPN protocol selection**.
- Co-operative scheduling of concurrent tasks using Ruby fibers.
- High-performance event reactor for handling I/O events and timers.
- Natural, sequential programming style that makes it easy to reason about
concurrent code.
-- Higher-order constructs for controlling the execution of concurrent code:
+- Abstractions and constructs for controlling the execution of concurrent code:
coprocesses, supervisors, cancel scopes, throttling, resource pools etc.
- Code can use native networking classes and libraries, growing support for
third-party gems such as `pg` and `redis`.
-- Comprehensive HTTP 1.0 / 1.1 / 2 client and server APIs.
-- Excellent performance and scalability characteristics, in terms of both
+- HTTP 1 / HTTP 2 client
+- Competitive performance and scalability characteristics, in terms of both
throughput and memory consumption.
## Prior Art
Polyphony draws inspiration from the following, in no particular order:
@@ -87,16 +89,16 @@
```
In the above example, both `sleep` calls will be executed concurrently, and thus
the program will take approximately only 1 second to execute. Note the lack of
any boilerplate relating to concurrency. Each `spawn` block starts a
-*coroutine*, and is executed in sequential manner.
+*coprocess*, and is executed in sequential manner.
-> **Coroutines - the basic unit of concurrency**: In Polyphony, concurrent
-> operations take place inside coroutines. A `Coroutine` is executed on top of a
-> `Fiber`, which allows it to be suspended whenever a blocking operation is
-> called, and resumed once that operation has been completed. Coroutines offer
+> **Coprocesses - the basic unit of concurrency**: In Polyphony, concurrent
+> operations take place inside coprocesses. A `Coprocess` is executed on top of
+> a `Fiber`, which allows it to be suspended whenever a blocking operation is
+> called, and resumed once that operation has been completed. Coprocesses offer
> significant advantages over threads - they consume only about 10KB, switching
> between them is much faster than switching threads, and literally millions of
> them can be spawned without affecting performance*. Besides, Ruby does not yet
> allow parallel execution of threads.
>
@@ -111,11 +113,11 @@
```ruby
require 'polyphony'
server = TCPServer.open(1234)
while client = server.accept
- # spawn starts a new coroutine on a separate fiber
+ # spawn starts a new coprocess on a separate fiber
spawn {
while data = client.read rescue nil
client.write(data)
end
}
@@ -126,14 +128,14 @@
- The code uses the native `TCPServer` class from Ruby's stdlib, to setup a TCP
server. The result of `server.accept` is also a native `TCPSocket` object.
There are no wrapper classes being used.
- The only hint of the code being concurrent is the use of `Kernel#spawn`,
- which starts a new coroutine on a dedicated fiber. This allows serving
+ which starts a new coprocess on a dedicated fiber. This allows serving
multiple clients at once. Whenever a blocking call is issued, such as
`#accept` or `#read`, execution is *yielded* to the event loop, which will
- resume only those coroutines which are ready to be resumed.
+ resume only those coprocesses which are ready to be resumed.
- Exception handling is done using the normal Ruby constructs `raise`, `rescue`
and `ensure`. Exceptions never go unhandled (as might be the case with Ruby
threads), and must be dealt with explicitly. An unhandled exception will cause
the Ruby process to exit.
@@ -222,13 +224,13 @@
In order to facilitate writing concurrent code, Polyphony provides additional
constructs that make it easier to spawn concurrent tasks and to control them.
`CancelScope` - an abstraction used to cancel the execution of one or more
-coroutines or supervisors. It usually works by defining a timeout for the
+coprocesses or supervisors. It usually works by defining a timeout for the
completion of a task. Any blocking operation can be cancelled, including
-a coroutine or a supervisor. The developer may choose to cancel with or without
+a coprocess or a supervisor. The developer may choose to cancel with or without
an exception with `cancel` or `move_on`, respectively. Cancel scopes are
typically started using `Kernel.cancel_after` and `Kernel.move_on`:
```ruby
def echoer(client)
@@ -259,13 +261,28 @@
Pool.acquire { |db| p db.query('select 1') }
}
}
```
-`Supervisor` - a class used to control one or more `Coroutine`s. It can be used
-to start, stop and restart multiple coroutines. A supervisor can also be
-used for awaiting the completion of multiple coroutines. It is usually started
+You can also call arbitrary methods on the resource pool, which will be
+delegated to the resource using `#method_missing`:
+
+```ruby
+# up to 5 concurrent connections
+Pool = Polyphony::ResourcePool.new(limit: 5) {
+ # the block sets up the resource
+ PG.connect(...)
+}
+
+1000.times {
+ spawn { p Pool.query('select 1') }
+}
+```
+
+`Supervisor` - a class used to control one or more `Coprocess`s. It can be used
+to start, stop and restart multiple coprocesses. A supervisor can also be
+used for awaiting the completion of multiple coprocesses. It is usually started
using `Kernel.supervise`:
```ruby
supervise { |s|
s.spawn { sleep 1 }
@@ -287,10 +304,10 @@
```
`Throttler` - a mechanism for throttling an arbitrary task, such as sending of
emails, or crawling a website. A throttler is normally created using
`Kernel.throttle`, and can even be used to throttle operations across multiple
-coroutines:
+coprocesses:
```ruby
server = Net.tcp_listen(1234)
throttler = throttle(rate: 10) # up to 10 times per second
\ No newline at end of file