$30 off During Our Annual Pro Sale. View Details »

High In Fiber - ShRUG November 2010

Jon Rowe
November 08, 2010

High In Fiber - ShRUG November 2010

Presentation on Fibers given to ShRUG in November 2010

Jon Rowe

November 08, 2010
Tweet

More Decks by Jon Rowe

Other Decks in Technology

Transcript

  1. High In Fiber
    ShRUG 8th November 2010
    @JonRowe

    View Slide

  2. Word To The Wise
    This is probably going to be short...
    But hopefully sweet...
    But hopefully sweet...
    Please ask questions...
    But I don't promise to answer them...

    View Slide

  3. High In Fiber?
    What's a Fiber?

    View Slide

  4. Fibers are...
    Lightweight
    Concurrency
    Control

    View Slide

  5. Fibers are not
    Threads
    The only way to do things

    View Slide

  6. Threads vs Fibers
    Round 1: Fight!
    Threads have a heavy setup cost

    View Slide

  7. Threads vs Fibers
    http://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html

    View Slide

  8. Threads vs Fibers
    http://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html

    View Slide

  9. Threads vs Fibers
    Ding! Ding! Round 2
    Scheduling

    View Slide

  10. Scheduling
    Threads are scheduled in time slices
    Controlled by the Scheduler

    View Slide

  11. Scheduling
    Fibers are co-operatively scheduled
    Controlled by you!

    View Slide

  12. Scheduling
    Consider the example of 2 sections of code
    competing for CPU time.
    One takes 50ms of cpu time
    The other takes 40ms of blocking something
    and 10ms of cpu time

    View Slide

  13. Scheduling
    Run side by side these 2 sections of code
    would take 100ms in total
    If we can cooperatively schedule them, we
    can compress that into just 60ms

    View Slide

  14. Scheduling
    http://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/

    View Slide

  15. Example

    View Slide

  16. Example

    View Slide

  17. What does that do
    Create the fiber and assign it a block to execute

    View Slide

  18. What does that do
    In that block loop forever and double x

    View Slide

  19. What does that do
    Except each iteration we yield x

    View Slide

  20. What does that do?
    Creating the fiber does not execute the fiber
    To kick start the fiber we must `resume` it
    The first call to resume starts the
    execution of the fiber's block

    View Slide

  21. What does that do?
    Once executed the fiber follows normal
    behaviour
    Until it reaches `Fiber.yield`
    Upon which it "returns" the passed
    parameter
    Which drops out the resume

    View Slide

  22. Example
    The next call resuming from the yield will hit
    the bottom of the loop and carry on giving
    us

    View Slide

  23. Example
    f.resume => 2
    f.resume => 4
    f.resume => 8
    f.resume => 16

    View Slide

  24. Execution flow

    View Slide

  25. Execution flow
    $ puts f.resume "Cows"
    Initial resume value was => Cows
    initial yield value
    => nil

    View Slide

  26. Execution flow
    $ puts f.resume "Cats"
    Then you resumed me with Cats
    second yield value
    => nil

    View Slide

  27. Execution flow
    $ puts f.resume "Dogs"
    Finally you resumed me with Dogs
    => nil

    View Slide

  28. Execution flow
    $ puts f.resume "Zombies"
    FiberError: dead fiber called

    View Slide

  29. All Good?

    View Slide

  30. Fiber Pool
    Ok so lets try a more complex example

    View Slide

  31. Fiber Pool
    Say we have a blocking operation we want to
    run concurrently
    But we only want to do a certain number at
    the same time
    Let us invent a pool of worker fibers to do
    this cooperatively

    View Slide

  32. Fiber Pool

    View Slide

  33. Fiber Pool
    pool_size is going to be our concurrency limit

    View Slide

  34. Fiber Pool
    fibers is going to contain our stack of fibers

    View Slide

  35. Fiber Pool
    control_fiber is going to be our scheduler

    View Slide

  36. Fiber Pool
    Fiber.current gets the fiber we are currently in the
    execution scope of

    View Slide

  37. Fiber Pool
    If not specifically declared this is the root fiber of ruby
    itself

    View Slide

  38. Fiber Pool
    We need some way to add work to our pool

    View Slide

  39. Fiber Pool
    We create a new fiber to wrap our work item

    View Slide

  40. Fiber Pool
    The fiber defines a completion_callback to transfer
    execution control back to the control fiber

    View Slide

  41. Fiber Pool
    Which passes itself back to the control_fiber

    View Slide

  42. Fiber Pool
    Our fiber then calls the block with
    completion_callback to perform our work

    View Slide

  43. Fiber Pool
    Once the fiber is setup
    We add it to the pool
    The fiber has not yet been run

    View Slide

  44. Fiber Pool
    add_to_pool first checks to see if the pool is
    over_capacity?
    If it is we wait_for_free_pool_space
    Otherwise we add our fiber into our pool
    And then we execute it

    View Slide

  45. Fiber Pool

    View Slide

  46. Fiber Pool
    wait_for_free_pool_space does two
    things
    calls wait_for_next_complete_fiber
    removes the completed fiber from the pool
    How does this work? If we look at our new
    fiber

    View Slide

  47. Fiber Pool

    View Slide

  48. Fiber Pool
    Remember that our completion_callback
    returns our fiber
    The idea is that when our work has finished
    it calls our completion_callback
    Which returns control to the control_fibe
    Which then pops out the completed fiber to
    the Fiber.yield in wait_for_next_complete_fiber

    View Slide

  49. Fiber Pool
    Now we can add fibers to our pool
    Now we need to tidy up some loose ends

    View Slide

  50. Fiber Pool

    View Slide

  51. Fiber Pool

    View Slide

  52. Fiber Pool

    View Slide

  53. Fiber Pool
    fibers_left_to_process? we haven't used that
    anywhere?
    In order to actually use our pool we need
    one more method

    View Slide

  54. Fiber Pool

    View Slide

  55. Fiber Pool
    Once we have finished adding work to our
    pool we need someway to handle the
    remaining finishing fibers
    We need to tidy up after ourselves
    We need to drain the pool

    View Slide

  56. Fiber Pool

    View Slide

  57. Fiber Pool
    All we are doing here is checking if there are
    fibers still ticking
    And waiting until they are finished

    View Slide

  58. Fiber Pool
    Now we can use our fiber pool
    But it will need some setup
    So lets make a convenience wrapper

    View Slide

  59. Fiber Pool

    View Slide

  60. Fiber Pool
    We create the fiber which is to be our
    control_fiber
    We create a new pool
    We yield that pool to whatever code we are
    setting up

    View Slide

  61. Fiber Pool
    We drain the pool
    We cheat and call EM.stop, I'll cover that in
    a bit
    We immediately execute our fiber

    View Slide

  62. Fiber Pool
    Let’s use the pool

    View Slide

  63. Fiber Pool

    View Slide

  64. Caveat
    The EventMachine.run block is why we need
    the EM.stop command
    We eventually want to drop out of
    EventMachine
    I'm using EventMachine for notifying my fiber
    pool when my blocking command finishes
    We could use something else

    View Slide

  65. Fiber Pool

    View Slide

  66. Fiber Pool
    We use our convenience method to start our
    fiber pool
    We take our created pool and we're going to add
    30 tasks
    Each task is going to be simulating blocking
    operation by sleeping for 5 seconds
    When the blocking operation is complete we are
    going to call the completion_callback

    View Slide

  67. The result?
    For comparison lets look at it conventionally
    first

    View Slide

  68. The result?

    View Slide

  69. The result?

    View Slide

  70. The result?
    What should have taken 150 seconds
    Has taken 15 seconds

    View Slide

  71. EventMachine?
    Where did that come from?

    View Slide

  72. EventMachine?
    Fibers are cooperatively scheduled
    That doesn't make them instantly intelligent
    We need something to wake them up
    appropriately

    View Slide

  73. EventMachine?
    I'm using EventMachine out of convenience
    It could be any control structure that can
    call f.resume

    View Slide

  74. Evented IO
    Ideally I'd like to wake my fibers up directly
    upon receiving a message
    Then I don't have to have extra overhead

    View Slide

  75. References
    http://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html
    http://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/
    http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html
    http://pragdave.blogs.pragprog.com/pragdave/2008/01/pipelines-using.html
    http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/
    http://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/
    http://github.com/oldmoe/neverblock
    http://github.com/igrigorik << author of many of the event machine plugins

    View Slide

  76. Fin

    View Slide

  77. Questions?

    View Slide

  78. Pub!

    View Slide