Skip to content

cjbottaro/strand

Repository files navigation

strand

Strand is a class that wraps Fibers and gives them Thread-like behavior by using EventMachine.

Strand::ConditionVariable provides functionality for Fibers similar to Ruby’s built in ConditionVariable for Threads.

Like Threads

Strand has an interface similar to Thread.

thread = Thread.new{ 1+2 }
thread.join
thread.value # => 3

strand = Strand.new{ 1+2 }
strand.join
strand.value # => 3

Fiber/EventMachine aware sleep

Calling sleep usually results in EventMachine’s reactor being blocked, but Strand defines an EM+Fiber safe sleep.

Consider mimicking the following threaded code:

t1 = Thread.new{ sleep(1) }
t2 = Thread.new{ sleep(1) }
t1.join
t2.join
# Roughly 1 second will have passed.

Assuming that EventMachine is running:

s1 = Strand.new{ Strand.sleep(1) }
s2 = Strand.new{ Strand.sleep(1) }
s1.join
s2.join
# Roughly 1 second will have passed.

Thread local, Fiber local and Strand local variables

Thread local storage is the same as Fiber local storage in Ruby.

Thread.current[:name] = "callie"
Fiber.current[:name]  # => "callie"
Fiber.current[:name]  = "coco"
Thread.current[:name] # => "coco"

Strand provides its own storage.

Thread.current[:name] = "callie"
Strand.current[:name] = "coco"
Thread.current[:name] # => "callie"
Strand.current[:name] # => "coco"

Strand.list

Ruby provides a way to get a list of all living Threads:

Thread.new{ sleep }
Thread.list # => [#<Thread:0x007f9343869da8 run>, #<Thread:0x007f934405eec8 sleep>]

There is no equivalent for finding all living Fibers.

There is a way to find all living Strands though:

Strand.new do
  Strand.new{ Strand.yield }
  Strand.list # => [#<Strand:0x70358087608460 run, #<Strand:0x70358087608280 yielded]
end

Strand.pass

Consider the following threaded code:

Thread.new do
  puts 1
  Thread.pass
  puts 2
  Thread.pass
  puts 3
end
Thread.new do
  puts 1
  Thread.pass
  puts 2
  Thread.pass
  puts 3
end

Or similarly:

Thread.new do
  puts 1
  sleep(0.01)
  puts 2
  sleep(0.01)
  puts 3
end
Thread.new do
  puts 1
  sleep(0.01)
  puts 2
  sleep(0.01)
  puts 3
end

How would you do that with fibers?

Fiber.new do
  puts 1
  Fiber.yield
  puts 2
  Fiber.yield
  puts 3
end.resume
Fiber.new do
  puts 1
  Fiber.yield
  puts 2
  Fiber.yield
  puts 3
end.resume

That doesn’t work. The fibers are yielding, but nothing is resuming them. The output is just:

1
1

Enter Strand.pass. It yields the fiber, but tells EventMachine to resume it on the next tick.

Strand.new do
  puts 1
  Strand.pass
  puts 2
  Strand.pass
  puts 3
end
Strand.new do
  puts 1
  Strand.pass
  puts 2
  Strand.pass
  puts 3
end

The output is:

1
1
2
2
3
3

RDoc

http://doc.stochasticbytes.com/strand/index.html

Contributing to strand

  • Check out the latest master to make sure the feature hasn’t been implemented or the bug hasn’t been fixed yet

  • Check out the issue tracker to make sure someone already hasn’t requested it and/or contributed it

  • Fork the project

  • Start a feature/bugfix branch

  • Commit and push until you are happy with your contribution

  • Make sure to add tests for it. This is important so I don’t break it in a future version unintentionally.

  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

Copyright © 2011 Christopher J. Bottaro. See LICENSE.txt for further details.

About

Make fibers behave like threads using EventMachine.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages