Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
777 additions
and
194 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,6 @@ | ||
--protected --no-private --embed-mixins --output-dir ./doc --markup markdown | ||
--protected | ||
--no-private | ||
--embed-mixins | ||
--output-dir ./doc | ||
--markup markdown | ||
--use-cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
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 'concurrent/actress' | ||
Concurrent::Actress.i_know_it_is_experimental! | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
class Counter | ||
# Include context of an actor which gives this class access to reference and other information | ||
# about the actor, see CoreDelegations. | ||
include Concurrent::Actress::Context | ||
|
||
# use initialize as you wish | ||
def initialize(initial_value) | ||
@count = initial_value | ||
end | ||
|
||
# override on_message to define actor's behaviour | ||
def on_message(message) | ||
case message | ||
when Integer | ||
@count += message | ||
when :terminate | ||
terminate! | ||
else | ||
raise 'unknown' | ||
end | ||
end | ||
end | ||
|
||
# Create new actor naming the instance 'first'. | ||
# Return value is a reference to the actor, the actual actor is never returned. | ||
counter = Counter.spawn(:first, 5) | ||
|
||
# Tell a message and forget returning self. | ||
counter.tell(1) | ||
counter << 1 | ||
# (First counter now contains 7.) | ||
|
||
# Send a messages asking for a result. | ||
counter.ask(0).class | ||
counter.ask(0).value | ||
|
||
# Terminate the actor. | ||
counter.tell(:terminate) | ||
# Not terminated yet, it takes a while until the message is processed. | ||
counter.terminated? | ||
# Waiting for the termination. | ||
counter.terminated.class | ||
counter.terminated.wait | ||
counter.terminated? | ||
# Any subsequent messages are rejected. | ||
counter.ask(5).wait.rejected? | ||
|
||
# Failure on message processing terminates the actor. | ||
counter = Counter.spawn(:first, 0) | ||
counter.ask('boom').wait.rejected? | ||
counter.terminated? | ||
|
||
|
||
# Lets define an actor creating children actors. | ||
class Node | ||
include Concurrent::Actress::Context | ||
|
||
def on_message(message) | ||
case message | ||
when :new_child | ||
spawn self.class, :child | ||
when :children | ||
children | ||
when :terminate | ||
terminate! | ||
else | ||
raise 'unknown' | ||
end | ||
end | ||
end | ||
|
||
# Actors are tracking parent-child relationships | ||
parent = Node.spawn :parent | ||
child = parent.ask!(:new_child) | ||
child.parent | ||
parent.ask!(:children) | ||
|
||
# There is a special root actor which is used for all actors spawned outside any actor. | ||
parent.parent | ||
|
||
# Termination of an parent will also terminate all children. | ||
parent.ask('boom').wait # | ||
parent.terminated? | ||
child.terminated? |
Oops, something went wrong.