Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actress post release fixes #100

Merged
merged 13 commits into from Jun 14, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -6,7 +6,7 @@ tests.txt
.ruby-gemset
.bundle/*
.yardoc/*
doc/*
yardoc/*
tmp/*
man/*
*.tmproj
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -15,3 +15,4 @@ matrix:
- rvm: ruby-head
- rvm: jruby-head
- rvm: 1.9.3
script: "bundle exec rspec --color --backtrace --seed 1 --format documentation ./spec"
14 changes: 13 additions & 1 deletion .yardopts
@@ -1 +1,13 @@
--protected --no-private --embed-mixins --output-dir ./doc --markup markdown
--protected
--no-private
--embed-mixins
--output-dir ./yardoc
--markup markdown
--title=Concurrent Ruby
--template default
--template-path ./yard-template

./lib/**/*.rb
-
README.md
LICENSE.txt
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -8,6 +8,7 @@ group :development do
gem 'countloc', '~> 0.4.0', platforms: :mri
gem 'yard', '~> 0.8.7.4'
gem 'inch', '~> 0.4.1', platforms: :mri
gem 'redcarpet', platforms: :mri # understands github markdown
end

group :testing do
Expand Down
File renamed without changes.
73 changes: 38 additions & 35 deletions README.md
Expand Up @@ -2,57 +2,59 @@
[![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)

<table>
<tr>
<td align="left" valign="top">
<p>
Modern concurrency tools for Ruby. Inspired by
<a href="http://www.erlang.org/doc/reference_manual/processes.html">Erlang</a>,
<a href="http://clojure.org/concurrent_programming">Clojure</a>,
<a href="http://www.scala-lang.org/api/current/index.html#scala.actors.Actor">Scala</a>,
<a href="http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell">Haskell</a>,
<a href="http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx">F#</a>,
<a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx">C#</a>,
<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">Java</a>,
and classic concurrency patterns.
</p>
<p>
The design goals of this gem are:
<ul>
<li>Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why</li>
<li>Remain free of external gem dependencies</li>
<li>Stay true to the spirit of the languages providing inspiration</li>
<li>But implement in a way that makes sense for Ruby</li>
<li>Keep the semantics as idiomatic Ruby as possible</li>
<li>Support features that make sense in Ruby</li>
<li>Exclude features that don't make sense in Ruby</li>
<li>Be small, lean, and loosely coupled</li>
</ul>
</p>
</td>
<td align="right" valign="top">
<img src="https://raw.githubusercontent.com/wiki/ruby-concurrency/concurrent-ruby/logo/concurrent-ruby-logo-300x300.png"/>
</td>
</tr>
<tr>
<td align="left" valign="top">
<p>
Modern concurrency tools for Ruby. Inspired by
<a href="http://www.erlang.org/doc/reference_manual/processes.html">Erlang</a>,
<a href="http://clojure.org/concurrent_programming">Clojure</a>,
<a href="http://www.scala-lang.org/api/current/index.html#scala.actors.Actor">Scala</a>,
<a href="http://www.haskell.org/haskellwiki/Applications_and_libraries/Concurrency_and_parallelism#Concurrent_Haskell">Haskell</a>,
<a href="http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx">F#</a>,
<a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx">C#</a>,
<a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">Java</a>,
and classic concurrency patterns.
</p>
<p>
The design goals of this gem are:
<ul>
<li>Be an 'unopinionated' toolbox that provides useful utilities without debating which is better or why</li>
<li>Remain free of external gem dependencies</li>
<li>Stay true to the spirit of the languages providing inspiration</li>
<li>But implement in a way that makes sense for Ruby</li>
<li>Keep the semantics as idiomatic Ruby as possible</li>
<li>Support features that make sense in Ruby</li>
<li>Exclude features that don't make sense in Ruby</li>
<li>Be small, lean, and loosely coupled</li>
</ul>
</p>
</td>
<td align="right" valign="top">
<img src="https://raw.githubusercontent.com/wiki/ruby-concurrency/concurrent-ruby/logo/concurrent-ruby-logo-300x300.png"/>
</td>
</tr>
</table>

### Install
## Install

```shell
gem install concurrent-ruby
```

or add the following line to Gemfile:

```ruby
gem 'concurrent-ruby'
```

and run `bundle install` from your shell.

*NOTE: There is an old gem from 2007 called "concurrent" that does not appear to be under active development. That isn't us. Please do not run* `gem install concurrent`*. It is not the droid you are looking for.*
_NOTE: There is an old gem from 2007 called "concurrent" that does not appear to be under active development. That isn't us. Please do not run* `gem install concurrent`*. It is not the droid you are looking for._

## Features & Documentation

Please see the [Concurrent Ruby Wiki](https://github.com/ruby-concurrency/concurrent-ruby/wiki)
or the [API documentation](http://rubydoc.info/github/ruby-concurrency/concurrent-ruby/master/frames)
or the [API documentation](http://ruby-concurrency.github.io/concurrent-ruby/frames.html))
for more information or join our [mailing list](http://groups.google.com/group/concurrent-ruby).

There are many concurrency abstractions in this library. These abstractions can be broadly categorized
Expand All @@ -74,6 +76,7 @@ into several general groups:
* Thread synchronization classes and algorithms including [dataflow](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Dataflow),
timeout, condition, countdown latch, dependency counter, and event
* Java-inspired [thread pools](https://github.com/ruby-concurrency/concurrent-ruby/wiki/Thread%20Pools)
* New fast light-weighted [Actor model](http://ruby-concurrency.github.io/concurrent-ruby/frames.html#!Concurrent/Actress.html) implementation.
* And many more...

### Semantic Versioning
Expand All @@ -91,7 +94,7 @@ It should be fully compatible with any interpreter that is compliant with Ruby 1
Many more code examples can be found in the documentation for each class (linked above).
This one simple example shows some of the power of this gem.

```ruby
```ruby
require 'concurrent'
require 'thread' # for Queue
require 'open-uri' # for open(uri)
Expand Down
96 changes: 96 additions & 0 deletions doc/actress/celluloid_benchmark.rb
@@ -0,0 +1,96 @@
require 'benchmark'
require 'concurrent/actress'
Concurrent::Actress.i_know_it_is_experimental!
require 'celluloid'
require 'celluloid/autostart'

logger = Logger.new($stderr)
logger.level = Logger::INFO
Concurrent.configuration.logger = lambda do |level, progname, message = nil, &block|
logger.add level, message, progname, &block
end

scale = 1
ADD_TO = (100 * scale).to_i
counts_size = (500 * scale).to_i
adders_size = (500 * scale).to_i

class Counter
include Celluloid

def initialize(adders, i)
@adders = adders
@i = i
end

def counting(count, ivar)
if count < ADD_TO
@adders[(@i+1) % @adders.size].counting count+1, ivar
else
ivar.set count
end
end
end

threads = []

Benchmark.bmbm(10) do |b|
[2, adders_size, adders_size*2, adders_size*3].each do |adders_size|

b.report(format('%5d %4d %s', ADD_TO*counts_size, adders_size, 'actress')) do
counts = Array.new(counts_size) { [0, Concurrent::IVar.new] }
adders = Array.new(adders_size) do |i|
Concurrent::Actress::AdHoc.spawn("adder#{i}") do
lambda do |(count, ivar)|
if count.nil?
terminate!
else
if count < ADD_TO
adders[(i+1) % adders_size].tell [count+1, ivar]
else
ivar.set count
end
end
end
end
end

counts.each_with_index do |count, i|
adders[i % adders_size].tell count
end

counts.each do |count, ivar|
raise unless ivar.value >= ADD_TO
end

threads << Thread.list.size

adders.each { |a| a << [nil, nil] }
end

b.report(format('%5d %4d %s', ADD_TO*counts_size, adders_size, 'celluloid')) do
counts = []
counts_size.times { counts << [0, Concurrent::IVar.new] }

adders = []
adders_size.times do |i|
adders << Counter.new(adders, i)
end

counts.each_with_index do |count, i|
adders[i % adders_size].counting *count
end

counts.each do |count, ivar|
raise unless ivar.value >= ADD_TO
end

threads << Thread.list.size

adders.each(&:terminate)
end
end
end

p threads

75 changes: 75 additions & 0 deletions doc/actress/format.rb
@@ -0,0 +1,75 @@
require 'rubygems'
require 'bundler/setup'
require 'pry'
require 'pp'

input_paths = if ARGV.empty?
Dir.glob("#{File.dirname(__FILE__)}/*.in.rb")
else
ARGV
end.map { |p| File.expand_path p }

input_paths.each_with_index do |input_path, i|

pid = fork do
require_relative 'init.rb'

begin
output_path = input_path.gsub /\.in\.rb$/, '.out.rb'
input = File.readlines(input_path)

chunks = []
line = ''

while !input.empty?
line += input.shift
if Pry::Code.complete_expression? line
chunks << line
line = ''
end
end

raise unless line.empty?

chunks.map! { |chunk| [chunk, [chunk.split($/).size, 1].max] }
environment = Module.new.send :binding
evaluate = ->(code, line) do
eval(code, environment, input_path, line)
end

indent = 50

line_count = 1
output = ''
chunks.each do |chunk, lines|
result = evaluate.(chunk, line_count)
unless chunk.strip.empty? || chunk =~ /\A *#/
pre_lines = chunk.lines.to_a
last_line = pre_lines.pop
output << pre_lines.join

if last_line =~ /\#$/
output << last_line.gsub(/\#$/, '')
else
if last_line.size < indent && result.inspect.size < indent
output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"]
else
output << last_line << " # => #{result.inspect}\n"
end
end
else
output << chunk
end
line_count += lines
end

puts "#{input_path}\n -> #{output_path}"
#puts output
File.write(output_path, output)
rescue => ex
puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}"
end
end

Process.wait pid
end
2 changes: 2 additions & 0 deletions doc/actress/init.rb
@@ -0,0 +1,2 @@
require 'concurrent/actress'
Concurrent::Actress.i_know_it_is_experimental!