Skip to content

Commit ff37c93

Browse files
committed
Merge remote-tracking branch 'upstream/master' into actress
* upstream/master: (14 commits) Added another dataflow example from the wiki. ...
2 parents 741d3ac + eeb265d commit ff37c93

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1497
-223
lines changed

CHANGELOG.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
### Upcoming Release v0.7.1 (TBD)
2+
3+
Please see the [roadmap](https://github.com/ruby-concurrency/concurrent-ruby/issues/142) for more information on the next planned release.
4+
5+
* Added `flat_map` method to `Promise`
6+
* Added `zip` method to `Promise`
7+
* Fixed bug with logging in `Actor`
8+
* Improvements to `Promise` tests
9+
* Removed actor-experimental warning
10+
* Added an `IndirectImmediateExecutor` class
11+
* Allow disabling auto termination of global executors
12+
* Fix thread leaking in `ThreadLocalVar` (uses `Ref` gem on non-JRuby systems)
13+
* Fix thread leaking when pruning pure-Ruby thread pools
14+
* Prevent `Actor` from using an `ImmediateExecutor` (causes deadlock)
15+
* Added missing synchronizations to `TimerSet`
16+
* Fixed bug with return value of `Concurrent::Actor::Utils::Pool#ask`
17+
* Removed confusing warning when not using native extenstions
18+
* Improved documentation
19+
20+
## Current Release v0.7.0 (13 August 2014)
21+
22+
* Merge the [atomic](https://github.com/ruby-concurrency/atomic) gem
23+
- Pure Ruby `MutexAtomic` atomic reference class
24+
- Platform native atomic reference classes `CAtomic`, `JavaAtomic`, and `RbxAtomic`
25+
- Automated [build process](https://github.com/ruby-concurrency/rake-compiler-dev-box)
26+
- Fat binary releases for [multiple platforms](https://rubygems.org/gems/concurrent-ruby/versions) including Windows (32/64), Linux (32/64), OS X (64-bit), Solaris (64-bit), and JRuby
27+
* C native `CAtomicBoolean`
28+
* C native `CAtomicFixnum`
29+
* Refactored intermittently failing tests
30+
* Added `dataflow!` and `dataflow_with!` methods to match `Future#value!` method
31+
* Better handling of timeout in `Agent`
32+
* Actor Improvements
33+
- Fine-grained implementation using chain of behaviors. Each behavior is responsible for single aspect like: `Termination`, `Pausing`, `Linking`, `Supervising`, etc. Users can create custom Actors easily based on their needs.
34+
- Supervision was added. `RestartingContext` will pause on error waiting on its supervisor to decide what to do next ( options are `:terminate!`, `:resume!`, `:reset!`, `:restart!`). Supervising behavior also supports strategies `:one_for_one` and `:one_for_all`.
35+
- Linking was added to be able to monitor actor's events like: `:terminated`, `:paused`, `:restarted`, etc.
36+
- Dead letter routing added. Rejected envelopes are collected in a configurable actor (default: `Concurrent::Actor.root.ask!(:dead_letter_routing)`)
37+
- Old `Actor` class removed and replaced by new implementation previously called `Actress`. `Actress` was kept as an alias for `Actor` to keep compatibility.
38+
- `Utils::Broadcast` actor which allows Publish–subscribe pattern.
39+
* More executors for managing serialized operations
40+
- `SerializedExecution` mixin module
41+
- `SerializedExecutionDelegator` for serializing *any* executor
42+
* Updated `Async` with serialized execution
43+
* Updated `ImmediateExecutor` and `PerThreadExecutor` with full executor service lifecycle
44+
* Added a `Delay` to root `Actress` initialization
45+
* Minor bug fixes to thread pools
46+
* Refactored many intermittently failing specs
47+
* Removed Java interop warning `executor.rb:148 warning: ambiguous Java methods found, using submit(java.lang.Runnable)`
48+
* Fixed minor bug in `RubyCachedThreadPool` overflow policy
49+
* Updated tests to use [RSpec 3.0](http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3)
50+
* Removed deprecated `Actor` class
51+
* Better support for Rubinius
52+
53+
### Release v0.6.1 (14 June 2014)
54+
55+
* Many improvements to `Concurrent::Actress`
56+
* Bug fixes to `Concurrent::RubyThreadPoolExecutor`
57+
* Fixed several brittle tests
58+
* Moved documentation to http://ruby-concurrency.github.io/concurrent-ruby/frames.html
59+
60+
### Release v0.6.0 (25 May 2014)
61+
62+
* Added `Concurrent::Observable` to encapsulate our thread safe observer sets
63+
* Improvements to new `Channel`
64+
* Major improvements to `CachedThreadPool` and `FixedThreadPool`
65+
* Added `SingleThreadExecutor`
66+
* Added `Current::timer` function
67+
* Added `TimerSet` executor
68+
* Added `AtomicBoolean`
69+
* `ScheduledTask` refactoring
70+
* Pure Ruby and JRuby-optimized `PriorityQueue` classes
71+
* Updated `Agent` behavior to more closely match Clojure
72+
* Observer sets support block callbacks to the `add_observer` method
73+
* New algorithm for thread creation in `RubyThreadPoolExecutor`
74+
* Minor API updates to `Event`
75+
* Rewritten `TimerTask` now an `Executor` instead of a `Runnable`
76+
* Fixed many brittle specs
77+
* Renamed `FixedThreadPool` and `CachedThreadPool` to `RubyFixedThreadPool` and `RubyCachedThreadPool`
78+
* Created JRuby optimized `JavaFixedThreadPool` and `JavaCachedThreadPool`
79+
* Consolidated fixed thread pool tests into `spec/concurrent/fixed_thread_pool_shared.rb` and `spec/concurrent/cached_thread_pool_shared.rb`
80+
* `FixedThreadPool` now subclasses `RubyFixedThreadPool` or `JavaFixedThreadPool` as appropriate
81+
* `CachedThreadPool` now subclasses `RubyCachedThreadPool` or `JavaCachedThreadPool` as appropriate
82+
* New `Delay` class
83+
* `Concurrent::processor_count` helper function
84+
* New `Async` module
85+
* Renamed `NullThreadPool` to `PerThreadExecutor`
86+
* Deprecated `Channel` (we are planning a new implementation based on [Go](http://golangtutorials.blogspot.com/2011/06/channels-in-go.html))
87+
* Added gem-level [configuration](http://robots.thoughtbot.com/mygem-configure-block)
88+
* Deprecated `$GLOBAL_THREAD_POOL` in lieu of gem-level configuration
89+
* Removed support for Ruby [1.9.2](https://www.ruby-lang.org/en/news/2013/12/17/maintenance-of-1-8-7-and-1-9-2/)
90+
* New `RubyThreadPoolExecutor` and `JavaThreadPoolExecutor` classes
91+
* All thread pools now extend the appropriate thread pool executor classes
92+
* All thread pools now support `:overflow_policy` (based on Java's [reject policies](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html))
93+
* Deprecated `UsesGlobalThreadPool` in lieu of explicit `:executor` option (dependency injection) on `Future`, `Promise`, and `Agent`
94+
* Added `Concurrent::dataflow_with(executor, *inputs)` method to support executor dependency injection for dataflow
95+
* Software transactional memory with `TVar` and `Concurrent::atomically`
96+
* First implementation of [new, high-performance](https://github.com/ruby-concurrency/concurrent-ruby/pull/49) `Channel`
97+
* `Actor` is deprecated in favor of new experimental actor implementation [#73](https://github.com/ruby-concurrency/concurrent-ruby/pull/73). To avoid namespace collision it is living in `Actress` namespace until `Actor` is removed in next release.
98+
99+
### Release v0.5.0
100+
101+
This is the most significant release of this gem since its inception. This release includes many improvements and optimizations. It also includes several bug fixes. The major areas of focus for this release were:
102+
103+
* Stability improvements on Ruby versions with thread-level parallelism ([JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/))
104+
* Creation of new low-level concurrency abstractions
105+
* Internal refactoring to use the new low-level abstractions
106+
107+
Most of these updates had no effect on the gem API. There are a few notable exceptions which were unavoidable. Please read the [release notes](API-Updates-in-v0.5.0) for more information.
108+
109+
Specific changes include:
110+
111+
* New class `IVar`
112+
* New class `MVar`
113+
* New class `ThreadLocalVar`
114+
* New class `AtomicFixnum`
115+
* New class method `dataflow`
116+
* New class `Condition`
117+
* New class `CountDownLatch`
118+
* New class `DependencyCounter`
119+
* New class `SafeTaskExecutor`
120+
* New class `CopyOnNotifyObserverSet`
121+
* New class `CopyOnWriteObserverSet`
122+
* `Future` updated with `execute` API
123+
* `ScheduledTask` updated with `execute` API
124+
* New `Promise` API
125+
* `Future` now extends `IVar`
126+
* `Postable#post?` now returns an `IVar`
127+
* Thread safety fixes to `Dereferenceable`
128+
* Thread safety fixes to `Obligation`
129+
* Thread safety fixes to `Supervisor`
130+
* Thread safety fixes to `Event`
131+
* Various other thread safety (race condition) fixes
132+
* Refactored brittle tests
133+
* Implemented pending tests
134+
* Added JRuby and Rubinius as Travis CI build targets
135+
* Added [CodeClimate](https://codeclimate.com/) code review
136+
* Improved YARD documentation

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Concurrent Ruby
2-
[![Gem Version](https://badge.fury.io/rb/concurrent-ruby.png)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://coveralls.io/repos/ruby-concurrency/concurrent-ruby/badge.png)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.png)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.png)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.png)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](http://img.shields.io/license/MIT.png?color=green)](http://opensource.org/licenses/MIT) [![Gitter chat](https://badges.gitter.im/ruby-concurrency/concurrent-ruby.png)](https://gitter.im/ruby-concurrency/concurrent-ruby)
2+
[![Gem Version](https://badge.fury.io/rb/concurrent-ruby.svg)](http://badge.fury.io/rb/concurrent-ruby) [![Build Status](https://travis-ci.org/ruby-concurrency/concurrent-ruby.svg?branch=master)](https://travis-ci.org/ruby-concurrency/concurrent-ruby) [![Coverage Status](https://img.shields.io/coveralls/ruby-concurrency/concurrent-ruby/master.svg)](https://coveralls.io/r/ruby-concurrency/concurrent-ruby) [![Code Climate](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby.svg)](https://codeclimate.com/github/ruby-concurrency/concurrent-ruby) [![Inline docs](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby.svg)](http://inch-ci.org/github/ruby-concurrency/concurrent-ruby) [![Dependency Status](https://gemnasium.com/ruby-concurrency/concurrent-ruby.svg)](https://gemnasium.com/ruby-concurrency/concurrent-ruby) [![License](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT) [![Gitter chat](http://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/ruby-concurrency/concurrent-ruby)
33

44
<table>
55
<tr>
@@ -30,7 +30,7 @@
3030
</p>
3131
</td>
3232
<td align="right" valign="top">
33-
<img src="https://raw.githubusercontent.com/wiki/ruby-concurrency/concurrent-ruby/logo/concurrent-ruby-logo-300x300.png"/>
33+
<img src="https://raw.githubusercontent.com/ruby-concurrency/concurrent-ruby/master/doc/logo/concurrent-ruby-logo-300x300.png"/>
3434
</td>
3535
</tr>
3636
</table>
@@ -74,8 +74,9 @@ This gem adheres to the rules of [semantic versioning](http://semver.org/).
7474
### Supported Ruby versions
7575

7676
MRI 1.9.3, 2.0, 2.1, JRuby (1.9 mode), and Rubinius 2.x.
77-
This library is pure Ruby and has no gem dependencies.
78-
It should be fully compatible with any interpreter that is compliant with Ruby 1.9.3 or newer.
77+
Although native code is used for performance optimizations on some platforms, all functionality
78+
is available in pure Ruby. This gem should be fully compatible with any interpreter that is
79+
compliant with Ruby 1.9.3 or newer.
7980

8081
### Examples
8182

@@ -163,7 +164,6 @@ The following gem builds will be built at every release:
163164
* concurrent-ruby-x.y.z-x86_64-linux.gem (Linux 64-bit)
164165
* concurrent-ruby-x.y.z-x86-mingw32.gem (Windows 32-bit)
165166
* concurrent-ruby-x.y.z-x64-mingw32.gem (Windows 64-bit)
166-
* concurrent-ruby-x.y.z-x86_64-darwin-13.gem (OS X)
167167
* concurrent-ruby-x.y.z-x86-solaris-2.11.gem (Solaris)
168168

169169
### Installing

concurrent-ruby.gemspec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ Gem::Specification.new do |s|
3131
end
3232

3333
s.required_ruby_version = '>= 1.9.3'
34+
35+
unless defined?(JRUBY_VERSION)
36+
s.add_dependency 'ref', '~> 1.0.5'
37+
end
3438
end

doc/agent.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
`Agent`s are inspired by [Clojure's](http://clojure.org/) [agent](http://clojure.org/agents) function. An `Agent` is a single atomic value that represents an identity. The current value of the `Agent` can be requested at any time (`deref`). Each `Agent` has a work queue and operates on the global thread pool (see below). Consumers can `post` code blocks to the `Agent`. The code block (function) will receive the current value of the `Agent` as its sole parameter. The return value of the block will become the new value of the `Agent`. `Agent`s support two error handling modes: fail and continue. A good example of an `Agent` is a shared incrementing counter, such as the score in a video game.
2+
3+
An `Agent` must be initialize with an initial value. This value is always accessible via the `value` (or `deref`) methods. Code blocks sent to the `Agent` will be processed in the order received. As each block is processed the current value is updated with the result from the block. This update is an atomic operation so a `deref` will never block and will always return the current value.
4+
5+
When an `Agent` is created it may be given an optional `validate` block and zero or more `rescue` blocks. When a new value is calculated the value will be checked against the validator, if present. If the validator returns `true` the new value will be accepted. If it returns `false` it will be rejected. If a block raises an exception during execution the list of `rescue` blocks will be seacrhed in order until one matching the current exception is found. That `rescue` block will then be called an passed the exception object. If no matching `rescue` block is found, or none were configured, then the exception will be suppressed.
6+
7+
`Agent`s also implement Ruby's [Observable](http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html). Code that observes an `Agent` will receive a callback with the new value any time the value is changed.
8+
9+
## Copy Options
10+
11+
Object references in Ruby are mutable. This can lead to serious problems when the value of an `Agent` is a mutable reference. Which is always the case unless the value is a `Fixnum`, `Symbol`, or similar "primative" data type. Each `Agent` instance can be configured with a few options that can help protect the program from potentially dangerous operations. Each of these options can be optionally set when the `Agent` is created:
12+
13+
* `:dup_on_deref` when true the `Agent` will call the `#dup` method on the `value` object every time the `#value` methid is called (default: false)
14+
* `:freeze_on_deref` when true the `Agent` will call the `#freeze` method on the `value` object every time the `#value` method is called (default: false)
15+
* `:copy_on_deref` when given a `Proc` object the `Proc` will be run every time the `#value` method is called. The `Proc` will be given the current `value` as its only parameter and the result returned by the block will be the return value of the `#value` call. When `nil` this option will be ignored (default: nil)
16+
17+
## Examples
18+
19+
A simple example:
20+
21+
```ruby
22+
require 'concurrent'
23+
24+
score = Concurrent::Agent.new(10)
25+
score.value #=> 10
26+
27+
score << proc{|current| current + 100 }
28+
sleep(0.1)
29+
score.value #=> 110
30+
31+
score << proc{|current| current * 2 }
32+
sleep(0.1)
33+
score.value #=> 220
34+
35+
score << proc{|current| current - 50 }
36+
sleep(0.1)
37+
score.value #=> 170
38+
```
39+
40+
With validation and error handling:
41+
42+
```ruby
43+
score = Concurrent::Agent.new(0).validate{|value| value <= 1024 }.
44+
rescue(NoMethodError){|ex| puts "Bam!" }.
45+
rescue(ArgumentError){|ex| puts "Pow!" }.
46+
rescue{|ex| puts "Boom!" }
47+
score.value #=> 0
48+
49+
score << proc{|current| current + 2048 }
50+
sleep(0.1)
51+
score.value #=> 0
52+
53+
score << proc{|current| raise ArgumentError }
54+
sleep(0.1)
55+
#=> puts "Pow!"
56+
score.value #=> 0
57+
58+
score << proc{|current| current + 100 }
59+
sleep(0.1)
60+
score.value #=> 100
61+
```
62+
63+
With observation:
64+
65+
```ruby
66+
bingo = Class.new{
67+
def update(time, score)
68+
puts "Bingo! [score: #{score}, time: #{time}]" if score >= 100
69+
end
70+
}.new
71+
72+
score = Concurrent::Agent.new(0)
73+
score.add_observer(bingo)
74+
75+
score << proc{|current| sleep(0.1); current += 30 }
76+
score << proc{|current| sleep(0.1); current += 30 }
77+
score << proc{|current| sleep(0.1); current += 30 }
78+
score << proc{|current| sleep(0.1); current += 30 }
79+
80+
sleep(1)
81+
#=> Bingo! [score: 120, time: 2013-07-22 21:26:08 -0400]
82+
```

0 commit comments

Comments
 (0)