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. An

    introduction

    to
    Denis Defreyne

    Ruby Wine

    April 13th, 2019
    Fibers

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. Photo by Harshil Gudka on Unsplash

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  12. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  15. Photo by Arleen wiese on Unsplash

    View full-size slide

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

    donkey

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    in `resume':

    dead fiber called

    (FiberError)

    View full-size slide

  22. Photo by Spencer Watson on Unsplash

    View full-size slide

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

    kangaroo


    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. Photo by Austin Elder on Unsplash

    View full-size slide

  29. Image by sandid from Pixabay

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  36. Image by Tracey Wong from Pixabay

    View full-size slide

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


    end
    f.resume('samoyed')

    samoyed

    View full-size slide

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

    arctic fox

    View full-size slide

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

    View full-size slide

  40. 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 full-size slide

  41. Image by coolcoolleah from Pixabay

    View full-size slide

  42. Photo by Jonatan Pie on Unsplash

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  46. Photo by Michael Payne on Unsplash

    View full-size slide

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


    View full-size slide

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

    raccoon

    View full-size slide

  49. 36
    f = Fiber.new do

    Fiber.yield('maine coon')

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

    View full-size slide

  50. 36
    f = Fiber.new do

    Fiber.yield('maine coon')

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

    View full-size slide

  51. Photo by Bee Felten-Leidel on Unsplash

    View full-size slide

  52. Photo by Gary Bendig on Unsplash

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  56. Three
    Practical
    Applications
    40

    View full-size slide

  57. 1.
    Generators
    41

    View full-size slide

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

    View full-size slide

  59. 43
    class PeopleDirectory
    end

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  62. 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 full-size slide

  63. 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 full-size slide

  64. 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 full-size slide

  65. 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 full-size slide

  66. 50
    class LinearCongruentialGenerator



    View full-size slide

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

    View full-size slide

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

    View full-size slide

  69. 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 full-size slide

  70. 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 full-size slide

  71. 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 full-size slide

  72. 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 full-size slide

  73. 57
    class LinearCongruentialGenerator
    # …


    def each
    end
    end



    View full-size slide

  74. 58
    class LinearCongruentialGenerator
    # …


    def each
    loop do
    end
    end
    end



    View full-size slide

  75. 59
    class LinearCongruentialGenerator
    # …


    def each
    loop do
    self.next
    end
    end
    end



    View full-size slide

  76. 60
    class LinearCongruentialGenerator
    # …


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



    View full-size slide

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



    View full-size slide

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


    rng =
    LinearCongruentialGenerator.new(123)


    View full-size slide

  79. 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 full-size slide

  80. 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 full-size slide

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





    View full-size slide

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





    View full-size slide

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





    View full-size slide

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





    View full-size slide

  85. 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 full-size slide

  86. 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 full-size slide

  87. 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 full-size slide

  88. 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 full-size slide

  89. 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 full-size slide

  90. 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 full-size slide

  91. 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 full-size slide

  92. 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 full-size slide

  93. 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 full-size slide

  94. 1.
    Generators ✓
    78

    View full-size slide

  95. 2.
    Resumable computation
    79

    View full-size slide

  96. 81
    def compile
    end

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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


    View full-size slide

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

    View full-size slide

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


    compile_page(page)




    end
    end

    View full-size slide

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

    View full-size slide

  105. 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 full-size slide

  106. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  111. 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 full-size slide

  112. 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 full-size slide

  113. 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 full-size slide

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

    View full-size slide

  115. 2.
    Resumable computation ✓
    103

    View full-size slide

  116. 3.
    Non-blocking I/O
    104

    View full-size slide

  117. 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 full-size slide

  118. 107
    Version 1
    (sequential)

    View full-size slide

  119. 108
    urls.each do |url|
    end

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  123. 112
    Version 2
    (threaded)

    View full-size slide

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

    View full-size slide

  125. 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 full-size slide

  126. 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 full-size slide

  127. 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 full-size slide

  128. 117
    Version 3
    (non-blocking IO)

    View full-size slide

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

    View full-size slide

  130. Sockets must never block.
    119
    CAUTION II

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  134. 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 full-size slide

  135. 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 full-size slide

  136. 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 full-size slide

  137. 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 full-size slide

  138. 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 full-size slide

  139. 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 full-size slide

  140. 129
    def connect_tcp(socket)
    end

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  145. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  148. 137
    IO.select(
    )

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  154. 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 full-size slide

  155. 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 full-size slide

  156. 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 full-size slide

  157. 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 full-size slide

  158. 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 full-size slide

  159. 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 full-size slide

  160. 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 full-size slide

  161. 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 full-size slide

  162. 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 full-size slide

  163. 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 full-size slide

  164. 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 full-size slide

  165. 154
    def connect_ssl(socket)
    end

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  170. 158
    require 'async'
    require 'async/http'

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  173. 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 full-size slide

  174. 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 full-size slide

  175. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  180. Now you know
    everything
    about Fibers.

    View full-size slide

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

    View full-size slide