What have you found for these years?

2012-12-09

Regarding Fibers

Sorry that I think I'm too excited to be talking with ko1,
so I decided to post this email on my blog except those
unrelated to fibers. Hope this might be helpful for some
others, too.

from: Lin Jen-Shin (godfat)
to: ko1
date: Sun, Dec 9, 2012 at 12:37 AM
subject: Regarding Fibers

Hi ko1 san,

We talked about fibers at rubyconf.tw/2012. It's really nice to be
chatting with you. I knew YARV for a long while, although I never
really read the source, but I am still quite interested in compiler
and virtual machine. I didn't expect I could talk with you in person :D
I am really happy about this.

There are a number of libraries I wrote involved with fibers, and
I'll list all of them. First I want to mention em-synchrony as I told
you yesterday, because actually I learned that fiber usage from
there.

And here's my slide if you missed it.
http://godfat.org/slide/2012-12-07-concurrent.pdf



# Fiber.current

Here's a very simple code demonstrates the idea, and this is
the reason why we would want `Fiber.current'.
simple-fiber-demo.rb
require 'eventmachine'
require 'fiber'

def process
  f = Fiber.current
  EM.add_timer(2){ puts "Time's Up!"; f.resume }
  Fiber.yield

  puts "Process Done!"
  EM.stop
end

EM.run{
  Fiber.new{
    # here i don't want to pass the fiber in, so Fiber.current would be useful
    process
  }.resume
}



# Fiber.root

And here's my code I showed you yesterday, which would need `Fiber.root'
Check if we're under a context of fiber or thread.
def self.create *args, &block
  if Fiber.respond_to?(:current) && RootFiber != Fiber.current &&
     # because under a thread, Fiber.current won't return the root fiber
     Thread.main == Thread.current
    FutureFiber .new(*args, &block)
  else
    FutureThread.new(*args, &block)
  end
end

So the idea is that I want to implement Futures.

Essentially whenever we do an HTTP request, rest-core would
pick whether to use FutureFiber or FutureThread depending on
the context automatically. Say that we're inside eventmachine's
event loop *and* a fiber, then I assume that the user would want
to use fibers. Otherwise if we're inside a thread, then I assume
the user want to use threads.

If we're inside a non-root fiber, then I assume that we're in a
context where there's a fiber wrapped around, and also we're
using eventmachine! So that I can `Fiber.yield' later on and keep
the reactor in eventmachine running, and only resume whenever
eventmachine has done its job.

You can read example/use-cases.rb for all possible use cases.
There are 4 different configurations:

* pure_ruby (thread)
* eventmachine_fiber
* eventmachine_thread
* eventmachine_rest_client (thread)



# Fiber#resumed? or Fiber#running? or Fiber#started?

I forgot to tell you that this method would be useful too.
Here's the code in FutureFiber.
current_fibers.each{ |f|
  next unless f.alive?
  next_tick{
    begin
      f.resume
    rescue FiberError
      # whenever timeout, it would be already resumed,
      # and we have no way to tell if it's already resumed or not!
    end
  }
}

It would be good that if we can tell the fiber is actually running or not.
`Fiber#alive?' cannot tell this. This happens when the HTTP is timed out
while the original callback cannot or hard to be canceled. That means,
we would hit `Fiber#resume' twice intentionally. It would be good that
we don't have to rescue FiberError and accidentally rescue `cannot yield
from root fiber' error. Well, should I parse the error message to distinguish
them? :P Reraise if it's a root fiber error where it should be a bug, but ignore
it if it's double resuming intentionally.

Better to have a check for that instead of using exception handling and
paring error messages.



# Fiber#[] for fiber local variables

Sorry that it seems I've already deleted the code because I dropped the
support for cool.io. The commit which removed it could be found here.
remove coolio support. sorry, i guess no one is using it :(

The exact code is:
Thread.current[:coolio_http_client].detach if
  Thread.current[:coolio_http_client].kind_of?(::Coolio::HttpFiber)

While this should be read `Fiber.current[:coolio_http_client]' here,
because this code is only used inside a fiber. The class name is
CoolioFiber :)

This is all for readability though.

p.s. I thought I used it in sync-defer, but apparently I have bad memory.
This gem is actually obsolete, no longer really used though.



# How we configure to use fibers in a web server.

I also want to show you this since you told me that you never
thought of using fibers this way. Here's my playground for various
server configurations. https://github.com/godfat/ruby-server-exp
The rack application is located at: config.ru
It's quite complicated because I tried to use the same application
for all possible configurations, so it's not quite readable.

The simplest configuration would be using Rainbows! with FiberSpawn
model, which located is here: rainbows-fiber-spawn.rb

And here's the script to launch the server: rainbows-fiber-spawn.sh
rainbows -E none -c config/rainbows-fiber-spawn.rb
Here's the code which define FiberSpawn in Rainbows! (The author is Eric Wong)
fiber_spawn.rb

Essentially it wraps every HTTP request in a fiber, so that we can yield
in the application and resume back whenever the resource is ready.

Celluloid is using fibers heavily, too.

I remember there's an issue that fiber stack is too small!
Actually we had the same issue before, since we're using Rails,
and you know that Rails has a quite huge call stack.....

I also know that in Ruby 2.0, under a 64bit machine, the stack
is much more larger than it was in 1.9.3. I am looking forward to it :D
Hope that would be large enough for such stack monster like Rails.



That's all what in my mind currently. Thank you so much for listening!
And sorry for writing it so long :P Personally I still like fibers a lot, the
idea is cool, and I think every language should have some coroutine
support. (maybe except Haskell though) It would be good that if we
could push it forward. Umm, Matz is not a thread guy, but a fiber guy? :P

[snip]

Cheers, and safe travel!

*

Doh, I should have remembered Goliath,
which is a step further from em-synchrony.

0 retries:

Post a Comment

All texts are licensed under CC Attribution 3.0