Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require 'concurrent/actress'
Concurrent::Actress.i_know_it_is_experimental!
Loading