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