Upgrade to Pro — share decks privately, control downloads, hide ads and more …

An introduction to fibers

An introduction to fibers

Denis Defreyne

April 13, 2019
Tweet

More Decks by Denis Defreyne

Other Decks in Technology

Transcript

  1. Fibers

    View Slide

  2. An

    introduction

    to
    Denis Defreyne

    Ruby Wine

    April 13th, 2019
    Fibers

    View Slide

  3. 3
    1.

    View Slide

  4. 3
    1. 2.

    View Slide

  5. Basics
    4

    View Slide

  6. 5
    f = lambda do
    puts "giraffe"
    end
    f.call

    View Slide

  7. 5
    f = lambda do
    puts "giraffe"
    end
    f.call
    giraffe

    View Slide

  8. 6
    f = Fiber.new do
    puts "giraffe"
    end
    f.resume

    View Slide

  9. 6
    f = Fiber.new do
    puts "giraffe"
    end
    f.resume
    giraffe

    View Slide

  10. Photo by Harshil Gudka on Unsplash

    View Slide

  11. 8
    f = lambda do
    puts "zebra"
    end
    f.call
    zebra

    View Slide

  12. 9
    f = lambda do
    puts "zebra"
    return
    puts "invisible zebra"
    end
    f.call

    View Slide

  13. 9
    f = lambda do
    puts "zebra"
    return
    puts "invisible zebra"
    end
    f.call
    zebra

    View Slide

  14. 10
    f = Fiber.new do
    puts "zebra"
    return
    puts "invisible zebra"
    end
    f.resume

    View Slide

  15. 10
    f = Fiber.new do
    puts "zebra"
    return
    puts "invisible zebra"
    end
    f.resume
    zebra

    View Slide

  16. 10
    f = Fiber.new do
    puts "zebra"
    return
    puts "invisible zebra"
    end
    f.resume
    zebra
    sample.rb:3:

    in `block in ':

    unexpected return

    (LocalJumpError)

    View Slide

  17. 11
    f = Fiber.new do
    puts "zebra"
    Fiber.yield
    puts "invisible zebra"
    end
    f.resume

    View Slide

  18. 11
    f = Fiber.new do
    puts "zebra"
    Fiber.yield
    puts "invisible zebra"
    end
    f.resume
    zebra

    View Slide

  19. Photo by Arleen wiese on Unsplash

    View Slide

  20. 13
    f = lambda do
    puts "donkey"
    end
    f.call

    donkey

    View Slide

  21. 14
    f = lambda do
    puts "donkey"
    end
    f.call
    f.call

    View Slide

  22. 14
    f = lambda do
    puts "donkey"
    end
    f.call
    f.call
    donkey
    donkey

    View Slide

  23. 15
    f = Fiber.new do
    puts "donkey"
    end
    f.resume
    f.resume

    View Slide

  24. 15
    f = Fiber.new do
    puts "donkey"
    end
    f.resume
    f.resume
    donkey

    View Slide

  25. 15
    f = Fiber.new do
    puts "donkey"
    end
    f.resume
    f.resume
    donkey
    a.rb:6:

    in `resume':

    dead fiber called

    (FiberError)

    View Slide

  26. Photo by Spencer Watson on Unsplash

    View Slide

  27. 17
    f = lambda do
    puts "kangaroo"
    return
    puts "wallaby"
    end
    f.call

    kangaroo


    View Slide

  28. 18
    f = lambda do
    puts "kangaroo"
    return
    puts "wallaby"
    end
    f.call
    f.call

    View Slide

  29. 18
    f = lambda do
    puts "kangaroo"
    return
    puts "wallaby"
    end
    f.call
    f.call
    kangaroo
    kangaroo

    View Slide

  30. 19
    f = Fiber.new do
    puts "kangaroo"
    Fiber.yield
    puts "wallaby"
    end
    f.resume
    f.resume

    View Slide

  31. 19
    f = Fiber.new do
    puts "kangaroo"
    Fiber.yield
    puts "wallaby"
    end
    f.resume
    f.resume
    kangaroo
    wallaby

    View Slide

  32. Photo by Austin Elder on Unsplash

    View Slide

  33. Image by sandid from Pixabay

    View Slide

  34. 22
    f = Fiber.new { … }
    Create a fiber

    View Slide

  35. 22
    f = Fiber.new { … }
    Create a fiber
    f.resume
    Start or resume a fiber

    View Slide

  36. 22
    f = Fiber.new { … }
    Create a fiber
    f.resume
    Start or resume a fiber
    Fiber.yield
    Return from a fiber

    View Slide

  37. 23
    f = Fiber.new do
    puts 'quokka'
    end
    f.resume
    quokka

    View Slide

  38. 24
    f = Fiber.new do |a|
    puts a
    end
    f.resume('quokka')

    View Slide

  39. 24
    f = Fiber.new do |a|
    puts a
    end
    f.resume('quokka')
    quokka

    View Slide

  40. Image by Tracey Wong from Pixabay

    View Slide

  41. 26
    f = Fiber.new do |a|
    puts a


    end
    f.resume('samoyed')

    samoyed

    View Slide

  42. 27
    f = Fiber.new do |a|
    puts a
    Fiber.yield
    puts 'arctic fox'
    end
    f.resume('samoyed')
    f.resume
    samoyed

    arctic fox

    View Slide

  43. 28
    f = Fiber.new do |a|
    puts a
    b = Fiber.yield
    puts b
    end
    f.resume('samoyed')
    f.resume('arctic fox')

    View Slide

  44. 28
    f = Fiber.new do |a|
    puts a
    b = Fiber.yield
    puts b
    end
    f.resume('samoyed')
    f.resume('arctic fox')
    samoyed
    arctic fox

    View Slide

  45. Image by coolcoolleah from Pixabay

    View Slide

  46. Photo by Jonatan Pie on Unsplash

    View Slide

  47. 31
    f = Fiber.new do
    puts 'red panda'
    end
    f.resume
    red panda

    View Slide

  48. 32
    f = Fiber.new do
    'red panda'
    end
    puts f.resume

    View Slide

  49. 32
    f = Fiber.new do
    'red panda'
    end
    puts f.resume
    red panda

    View Slide

  50. Photo by Michael Payne on Unsplash

    View Slide

  51. 34
    f = Fiber.new do
    puts 'maine coon'
    end
    f.resume
    maine coon


    View Slide

  52. 35
    f = Fiber.new do
    puts 'maine coon'
    Fiber.yield
    'raccoon'
    end
    f.resume
    puts f.resume
    maine coon

    raccoon

    View Slide

  53. 36
    f = Fiber.new do

    Fiber.yield('maine coon')

    'raccoon'
    end
    puts f.resume
    puts f.resume

    View Slide

  54. 36
    f = Fiber.new do

    Fiber.yield('maine coon')

    'raccoon'
    end
    puts f.resume
    puts f.resume
    maine coon
    raccoon

    View Slide

  55. Photo by Bee Felten-Leidel on Unsplash

    View Slide

  56. Photo by Gary Bendig on Unsplash

    View Slide

  57. 39
    f = Fiber.new { |…| … }
    Create a fiber

    View Slide

  58. 39
    f = Fiber.new { |…| … }
    Create a fiber
    r = f.resume(…)
    Start or resume a fiber

    View Slide

  59. 39
    f = Fiber.new { |…| … }
    Create a fiber
    r = f.resume(…)
    Start or resume a fiber
    a = Fiber.yield(…)
    Return from a fiber

    View Slide

  60. Three
    Practical
    Applications
    40

    View Slide

  61. 1.
    Generators
    41

    View Slide

  62. 42
    [7, 2, 4].each do |num|
    puts num
    end
    7
    2
    4

    View Slide

  63. 43
    class PeopleDirectory
    end

    View Slide

  64. 44
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    end

    View Slide

  65. 45
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    def each
    end
    end

    View Slide

  66. 46
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    def each
    yield RADIA
    yield KATIE
    yield ANITA
    end
    end

    View Slide

  67. 47
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    def each
    yield RADIA
    yield KATIE
    yield ANITA
    end
    end
    PeopleDirectory.new

    View Slide

  68. 48
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    def each
    yield RADIA
    yield KATIE
    yield ANITA
    end
    end
    PeopleDirectory.new.each do |name|
    puts name
    end

    View Slide

  69. 49
    class PeopleDirectory
    RADIA = 'Dr. Radia Perlman'
    KATIE = 'Dr. Katie Bouman'
    ANITA = 'Dr. Anita Borg'
    def each
    yield RADIA
    yield KATIE
    yield ANITA
    end
    end
    PeopleDirectory.new.each do |name|
    puts name
    end
    Dr. Radia Perlman
    Dr. Katie Bouman
    Dr. Anita Borg

    View Slide

  70. 50
    class LinearCongruentialGenerator



    View Slide

  71. 51
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345

    View Slide

  72. 52
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345
    def initialize(seed)
    @value = seed
    end

    View Slide

  73. 53
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345
    def initialize(seed)
    @value = seed
    end
    def next
    @value = (A * @value + C) % M
    end
    end

    View Slide

  74. 54
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345
    def initialize(seed)
    @value = seed
    end
    def next
    @value = (A * @value + C) % M
    end
    end
    rng =
    LinearCongruentialGenerator.new(123)

    View Slide

  75. 55
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345
    def initialize(seed)
    @value = seed
    end
    def next
    @value = (A * @value + C) % M
    end
    end
    rng =
    LinearCongruentialGenerator.new(123)
    p rng.next
    p rng.next
    p rng.next

    View Slide

  76. 56
    class LinearCongruentialGenerator
    M = 0x7FFFFFF
    A = 1103515245
    C = 12345
    def initialize(seed)
    @value = seed
    end
    def next
    @value = (A * @value + C) % M
    end
    end
    rng =
    LinearCongruentialGenerator.new(123)
    p rng.next
    p rng.next
    p rng.next
    440917719
    357222964
    2107447239

    View Slide

  77. 57
    class LinearCongruentialGenerator
    # …


    def each
    end
    end



    View Slide

  78. 58
    class LinearCongruentialGenerator
    # …


    def each
    loop do
    end
    end
    end



    View Slide

  79. 59
    class LinearCongruentialGenerator
    # …


    def each
    loop do
    self.next
    end
    end
    end



    View Slide

  80. 60
    class LinearCongruentialGenerator
    # …


    def each
    loop do
    self.next
    yield(@value)
    end
    end
    end



    View Slide

  81. 61
    class LinearCongruentialGenerator
    # …
    include Enumerable
    def each
    loop do
    self.next
    yield(@value)
    end
    end
    end



    View Slide

  82. 62
    class LinearCongruentialGenerator
    # …
    include Enumerable
    def each
    loop do
    self.next
    yield(@value)
    end
    end
    end


    rng =
    LinearCongruentialGenerator.new(123)


    View Slide

  83. 63
    class LinearCongruentialGenerator
    # …
    include Enumerable
    def each
    loop do
    self.next
    yield(@value)
    end
    end
    end


    rng =
    LinearCongruentialGenerator.new(123)

    p rng.take(3)

    View Slide

  84. 64
    class LinearCongruentialGenerator
    # …
    include Enumerable
    def each
    loop do
    self.next
    yield(@value)
    end
    end
    end


    rng =
    LinearCongruentialGenerator.new(123)

    p rng.take(3)
    [440917719,
    357222964,
    2107447239]

    View Slide

  85. 65
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345





    View Slide

  86. 66
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    end





    View Slide

  87. 67
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    end
    end





    View Slide

  88. 68
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    end
    end
    end





    View Slide

  89. 69
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    value = (A * value + C) % M
    end
    end
    end





    View Slide

  90. 70
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    value = (A * value + C) % M
    Fiber.yield(value)
    end
    end
    end





    View Slide

  91. 71
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    value = (A * value + C) % M
    Fiber.yield(value)
    end
    end
    end


    rng = make_rng(123)


    View Slide

  92. 72
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    value = (A * value + C) % M
    Fiber.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.resume

    p rng.resume

    p rng.resume

    View Slide

  93. 73
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Fiber.new do
    loop do
    value = (A * value + C) % M
    Fiber.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.resume

    p rng.resume

    p rng.resume
    440917719
    357222964
    2107447239

    View Slide

  94. 74
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Enumerator.new do |enum|
    loop do
    value = (A * value + C) % M
    enum.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.next

    p rng.next

    p rng.next
    440917719
    357222964
    2107447239

    View Slide

  95. 75
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Enumerator.new do |enum|
    loop do
    value = (A * value + C) % M
    enum.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.next

    p rng.next

    p rng.next
    440917719
    357222964
    2107447239

    View Slide

  96. 76
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Enumerator.new do |enum|
    loop do
    value = (A * value + C) % M
    enum.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.take(2)


    View Slide

  97. 77
    M = 0x7FFFFFFF
    A = 1103515245
    C = 12345
    def make_rng(value)
    Enumerator.new do |enum|
    loop do
    value = (A * value + C) % M
    enum.yield(value)
    end
    end
    end


    rng = make_rng(123)
    p rng.take(2)


    [440917719,
    357222964]

    View Slide

  98. 1.
    Generators ✓
    78

    View Slide

  99. 2.
    Resumable computation
    79

    View Slide

  100. 80

    View Slide

  101. 81
    def compile
    end

    View Slide

  102. 82
    def compile
    queue = PriorityQueue.new(pages)
    end

    View Slide

  103. 83
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    end
    end

    View Slide

  104. 84
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    end
    end

    View Slide

  105. 85
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    compile_page(page)
    end
    end

    View Slide

  106. 86

    View Slide

  107. 86



    View Slide

  108. 86



    View Slide

  109. 87
    def compiled_content_of(page)
    @compiled_content[page]
    end


    View Slide

  110. 88
    def compiled_content_of(page)
    unless @compiled_content.key?(page)
    raise MissingDependencyError.new(page)
    end
    @compiled_content[page]
    end

    View Slide

  111. 89
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next


    compile_page(page)




    end
    end

    View Slide

  112. 90
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    begin
    compile_page(page)
    rescue MissingDependencyError => error
    end
    end
    end

    View Slide

  113. 91
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    begin
    compile_page(page)
    rescue MissingDependencyError => error
    queue.add(page)
    end
    end
    end

    View Slide

  114. 92
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    begin
    compile_page(page)
    rescue MissingDependencyError => error
    queue.add(page)
    queue.prioritize(error.missing_page)
    end
    end
    end

    View Slide

  115. 93

    View Slide

  116. 93



    View Slide

  117. 93



    View Slide

  118. 93



    View Slide

  119. 93



    View Slide

  120. 93



    View Slide

  121. 93



    View Slide

  122. 93



    View Slide

  123. 94

    View Slide

  124. 94



    View Slide

  125. 94



    View Slide

  126. 94



    View Slide

  127. 94



    View Slide

  128. 94



    View Slide

  129. 95
    def fiber_for(page)
    @fibers[page] ||=
    Fiber.new { compile_page(page) }
    end

    View Slide

  130. 96
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    fiber_for(page).resume
    end
    end

    View Slide

  131. 97
    def compiled_content_of(page)
    unless @compiled_content.key?(page)
    Fiber.yield(MissingDependency.new(page))
    end
    @compiled_content[page]
    end

    View Slide

  132. 98
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    result = fiber_for(page).resume
    end
    end

    View Slide

  133. 99
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    result = fiber_for(page).resume
    if result.is_a?(MissingDependency)
    end
    end
    end

    View Slide

  134. 100
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    result = fiber_for(page).resume
    if result.is_a?(MissingDependency)
    queue.add(page)
    end
    end
    end

    View Slide

  135. 101
    def compile
    queue = PriorityQueue.new(pages)
    until queue.empty?
    page = queue.next
    result = fiber_for(page).resume
    if result.is_a?(MissingDependency)
    queue.add(page)
    queue.prioritize(result.missing_page)
    end
    end
    end

    View Slide

  136. 102
    def compiled_content_of(page)
    unless @compiled_content.key?(page)
    Fiber.yield(MissingDependency.new(page))
    end
    @compiled_content[page]
    end

    View Slide

  137. 2.
    Resumable computation ✓
    103

    View Slide

  138. 3.
    Non-blocking I/O
    104

    View Slide

  139. 105

    View Slide

  140. 106
    urls = [
    'https://denis.ws',
    'https://denis.ws/cv',
    'https://denis.ws/software',
    'https://denis.ws/talks',
    'https://denis.ws/toolbox',
    'https://nanoc.ws',

    ]

    View Slide

  141. 107
    Version 1
    (sequential)

    View Slide

  142. 108
    urls.each do |url|
    end

    View Slide

  143. 109
    urls.each do |url|
    response = Net::HTTP.get_response(URI.parse(url))
    end

    View Slide

  144. 110
    urls.each do |url|
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != "200"
    end
    end

    View Slide

  145. 111
    urls.each do |url|
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != "200"
    puts "Bad URL: #{url}"
    end
    end

    View Slide

  146. 112
    Version 2
    (threaded)

    View Slide

  147. 113
    urls.each do |url|
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != 200
    puts "Bad URL: #{url}"
    end
    end

    View Slide

  148. 114
    urls.each do |url|
    Thread.new do
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != 200
    puts "Bad URL: #{url}"
    end
    end
    end

    View Slide

  149. 115
    threads =
    urls.map do |url|
    Thread.new do
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != 200
    puts "Bad URL: #{url}"
    end
    end
    end

    View Slide

  150. 116
    threads =
    urls.map do |url|
    Thread.new do
    response = Net::HTTP.get_response(URI.parse(url))
    if response.code != 200
    puts "Bad URL: #{url}"
    end
    end
    end
    threads.each(&:join)

    View Slide

  151. 117
    Version 3
    (non-blocking IO)

    View Slide

  152. This is a low-level implementation.
    118
    CAUTION I

    View Slide

  153. Sockets must never block.
    119
    CAUTION II

    View Slide

  154. 120
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  155. 121
    def make_request_fiber(host, path)
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  156. 122
    def make_request_fiber(host, path)
    Fiber.new do
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  157. 123
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  158. 124
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  159. 125
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  160. 126
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    write(socket, build_http_request(host, path))
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  161. 127
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    write(socket, build_http_request(host, path))
    puts read(socket, 1024)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  162. 128
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    write(socket, build_http_request(host, path))
    puts read(socket, 1024)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  163. 129
    def connect_tcp(socket)
    end

    View Slide

  164. 130
    def connect_tcp(socket)
    socket.connect_tcp
    end

    View Slide

  165. 131
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    when :wait_writable
    else
    end
    end

    View Slide

  166. 132
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    Fiber.yield
    when :wait_writable
    else
    end
    end

    View Slide

  167. 133
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    Fiber.current
    Fiber.yield
    when :wait_writable
    else
    end
    end

    View Slide

  168. 134
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    when :wait_writable
    else
    end
    end

    View Slide

  169. 135
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  170. 136
    make_request_fiber('denis.ws', '/cv/').resume
    # … fiber got suspended; now what?

    View Slide

  171. 137
    IO.select(
    )

    View Slide

  172. 138
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )

    View Slide

  173. 139
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )

    View Slide

  174. 140
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )
    readable.each do |socket|
    end

    View Slide

  175. 141
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )
    readable.each do |socket|
    fiber = $awaiting_readable.fetch(socket)
    end

    View Slide

  176. 142
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )
    readable.each do |socket|
    fiber = $awaiting_readable.fetch(socket)
    fiber.resume
    end

    View Slide

  177. 143
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )
    readable.each do |socket|
    fiber = $awaiting_readable.fetch(socket)
    fiber.resume
    end
    writable.each do |socket|
    fiber = $awaiting_writable.fetch(socket)
    fiber.resume
    end

    View Slide

  178. 144
    loop do
    readable, writable =
    IO.select(
    $awaiting_readable.keys,
    $awaiting_writable.keys,
    )
    readable.each do |socket|
    fiber = $awaiting_readable.fetch(socket)
    fiber.resume
    end
    writable.each do |socket|
    fiber = $awaiting_writable.fetch(socket)
    fiber.resume
    end
    end

    View Slide

  179. 145
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    when :wait_writable
    else
    end
    end

    View Slide

  180. 146
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    else
    end
    end

    View Slide

  181. 147
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    Fiber.yield
    else
    end
    end

    View Slide

  182. 148
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    $awaiting_writable[socket] = Fiber.current
    Fiber.yield
    else
    end
    end

    View Slide

  183. 149
    def connect_tcp(socket)
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    $awaiting_writable[socket] = Fiber.current
    Fiber.yield
    $awaiting_writable.delete(socket)
    else
    end
    end

    View Slide

  184. 150
    def connect_tcp(socket)
    loop do
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    $awaiting_writable[socket] = Fiber.current
    Fiber.yield
    $awaiting_writable.delete(socket)
    else
    end
    end
    end

    View Slide

  185. 151
    def connect_tcp(socket)
    loop do
    case socket.connect_tcp
    when :wait_readable
    $awaiting_readable[socket] = Fiber.current
    Fiber.yield
    $awaiting_readable.delete(socket)
    when :wait_writable
    $awaiting_writable[socket] = Fiber.current
    Fiber.yield
    $awaiting_writable.delete(socket)
    else
    break
    end
    end
    end

    View Slide

  186. 152
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    write(socket, build_http_request(host, path))
    puts read(socket, 1024)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  187. 153
    def make_request_fiber(host, path)
    Fiber.new do
    socket = NonBlockingSSLSocket.new(host, 443)
    connect_tcp(socket)
    connect_ssl(socket)
    write(socket, build_http_request(host, path))
    puts read(socket, 1024)
    end
    end
    make_request_fiber('denis.ws', '/cv/').resume

    View Slide

  188. 154
    def connect_ssl(socket)
    end

    View Slide

  189. 155
    def connect_ssl(socket)
    socket.connect_ssl
    end

    View Slide

  190. 156
    def connect_ssl(socket)
    case socket.connect_ssl
    end

    View Slide

  191. 157
    def connect_ssl(socket)
    case socket.connect_ssl
    when :wait_readable
    when :wait_writable
    else
    end
    end

    View Slide

  192. 157
    def connect_ssl(socket)
    case socket.connect_ssl
    when :wait_readable
    when :wait_writable
    else
    end
    end

    View Slide

  193. 158
    require 'async'
    require 'async/http'

    View Slide

  194. 159
    require 'async'
    require 'async/http'
    endpoint = Async::HTTP::URLEndpoint.parse('https://denis.ws')

    View Slide

  195. 160
    require 'async'
    require 'async/http'
    endpoint = Async::HTTP::URLEndpoint.parse('https://denis.ws')
    client = Async::HTTP::Client.new(endpoint)

    View Slide

  196. 161
    require 'async'
    require 'async/http'
    endpoint = Async::HTTP::URLEndpoint.parse('https://denis.ws')
    client = Async::HTTP::Client.new(endpoint)
    Async do |task|
    end

    View Slide

  197. 162
    require 'async'
    require 'async/http'
    endpoint = Async::HTTP::URLEndpoint.parse('https://denis.ws')
    client = Async::HTTP::Client.new(endpoint)
    Async do |task|
    task.async { p client.get("/").status }
    task.async { p client.get("/cv/").status }
    task.async { p client.get("/software/").status }
    task.async { p client.get("/talks/").status }
    task.async { p client.get("/toolbox/").status }
    end

    View Slide

  198. 162
    require 'async'
    require 'async/http'
    endpoint = Async::HTTP::URLEndpoint.parse('https://denis.ws')
    client = Async::HTTP::Client.new(endpoint)
    Async do |task|
    task.async { p client.get("/").status }
    task.async { p client.get("/cv/").status }
    task.async { p client.get("/software/").status }
    task.async { p client.get("/talks/").status }
    task.async { p client.get("/toolbox/").status }
    end
    https://github.com/socketry/async

    View Slide

  199. 3.
    Non-blocking I/O ✓
    163

    View Slide

  200. 164
    1.

    View Slide

  201. 164
    1. 2.

    View Slide

  202. 164
    1. 2. 3.

    View Slide

  203. 165
    f = Fiber.new { |…| … }
    Create a fiber

    View Slide

  204. 165
    f = Fiber.new { |…| … }
    Create a fiber
    r = f.resume(…)
    Start or resume a fiber

    View Slide

  205. 165
    f = Fiber.new { |…| … }
    Create a fiber
    r = f.resume(…)
    Start or resume a fiber
    a = Fiber.yield(…)
    Return from a fiber

    View Slide

  206. Now you know
    everything
    about Fibers.

    View Slide

  207. Q&A
    Find me at @ddfreyne on Twitter, or at denis.ws!

    View Slide