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. 10 f = Fiber.new do puts "zebra" return puts "invisible

    zebra" end f.resume zebra sample.rb:3:
 in `block in <main>':
 unexpected return
 (LocalJumpError)
  2. 15 f = Fiber.new do puts "donkey" end f.resume f.resume

    donkey a.rb:6:
 in `resume':
 dead fiber called
 (FiberError)
  3. 18 f = lambda do puts "kangaroo" return puts "wallaby"

    end f.call f.call kangaroo kangaroo
  4. 22 f = Fiber.new { … } Create a fiber

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

    f.resume Start or resume a fiber Fiber.yield Return from a fiber
  6. 26 f = Fiber.new do |a| puts a
 
 end

    f.resume('samoyed')
 samoyed
  7. 27 f = Fiber.new do |a| puts a Fiber.yield puts

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

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

    Fiber.yield puts b end f.resume('samoyed') f.resume('arctic fox') samoyed arctic fox
  10. 35 f = Fiber.new do puts 'maine coon' Fiber.yield 'raccoon'

    end f.resume puts f.resume maine coon
 raccoon
  11. 39 f = Fiber.new { |…| … } Create a

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

    fiber r = f.resume(…) Start or resume a fiber a = Fiber.yield(…) Return from a fiber
  13. 44 class PeopleDirectory RADIA = 'Dr. Radia Perlman' KATIE =

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

    'Dr. Katie Bouman' ANITA = 'Dr. Anita Borg' def each end end
  15. 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
  16. 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
  17. 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
  18. 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
  19. 52 class LinearCongruentialGenerator M = 0x7FFFFFF A = 1103515245 C

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

    = 12345 def initialize(seed) @value = seed end def next @value = (A * @value + C) % M end end
  21. 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)
  22. 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
  23. 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
  24. 60 class LinearCongruentialGenerator # … 
 
 def each loop

    do self.next yield(@value) end end end
 
 

  25. 61 class LinearCongruentialGenerator # … include Enumerable def each loop

    do self.next yield(@value) end end end
 
 

  26. 62 class LinearCongruentialGenerator # … include Enumerable def each loop

    do self.next yield(@value) end end end
 
 rng = LinearCongruentialGenerator.new(123)

  27. 63 class LinearCongruentialGenerator # … include Enumerable def each loop

    do self.next yield(@value) end end end
 
 rng = LinearCongruentialGenerator.new(123)
 p rng.take(3)
  28. 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]
  29. 66 M = 0x7FFFFFFF A = 1103515245 C = 12345

    def make_rng(value) end
 
 
 
 

  30. 67 M = 0x7FFFFFFF A = 1103515245 C = 12345

    def make_rng(value) Fiber.new do end end
 
 
 
 

  31. 68 M = 0x7FFFFFFF A = 1103515245 C = 12345

    def make_rng(value) Fiber.new do loop do end end end
 
 
 
 

  32. 69 M = 0x7FFFFFFF A = 1103515245 C = 12345

    def make_rng(value) Fiber.new do loop do value = (A * value + C) % M end end end
 
 
 
 

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

  34. 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) 
 

  35. 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
  36. 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
  37. 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
  38. 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
  39. 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)
 

  40. 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]
  41. 80

  42. 86

  43. 86

  44. 86

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

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

    queue.next begin compile_page(page) rescue MissingDependencyError => error end end end
  47. 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
  48. 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
  49. 93

  50. 93

  51. 93

  52. 93

  53. 93

  54. 93

  55. 93

  56. 93

  57. 94

  58. 94

  59. 94

  60. 94

  61. 94

  62. 94

  63. 98 def compile queue = PriorityQueue.new(pages) until queue.empty? page =

    queue.next result = fiber_for(page).resume end end
  64. 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
  65. 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
  66. 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
  67. 105

  68. 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
  69. 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)
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 165 f = Fiber.new { |…| … } Create a

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

    fiber r = f.resume(…) Start or resume a fiber a = Fiber.yield(…) Return from a fiber