fiber_recycling 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 746dc55b0a096b0ae4cf0b155fd499ef0fd1ca5e
4
- data.tar.gz: 1846000c858ba6daa221bd38dd71249a6403fea3
3
+ metadata.gz: 630db3827d3b2a636f707e11f6595dc987627718
4
+ data.tar.gz: 33a112a7bdfbfc4e08daf71e45bf5ca2e35bed44
5
5
  SHA512:
6
- metadata.gz: ad2b976c652a19ab8ae5965f321b070fe5d4d47f6f2241532bc07bd84a4de37e22500707673ac7d2c7cb7e4411025f576e3506cacec5e75098a0b2c2ddb6d187
7
- data.tar.gz: 7ce95f737843b39d461b028b62b29d961ae7aabe1661c09497ee5464844cb28e836bdcb57aa673ee2fe021fd393f9c8f093d8b6a26df57651ac55f79f861dbcf
6
+ metadata.gz: 39a32ddb2a25f409eb60350a1dcdc1b56f6e70a92e12ea2fd1f8358989f10b8a663f2bdf325ea848d274c9187e350da3ef5a860b03e66166095fc3ae62c89529
7
+ data.tar.gz: 8eee84fc7780c79be520918267a1a3992fcaf06b2bedcda4662624c6e157d7c756d14d1be21860c5f1ddafcd728e21004cdf12fb20483995a2048157e1f3d52c
data/README.md CHANGED
@@ -1,2 +1,55 @@
1
- # Ruby Gem: FiberRecycling
2
- This gem offers a ducktype for `Fiber` that will reuse old native fibers for a small performance gain. It will work as a drop in replacment for Ruby's natve `Fiber`.
1
+ # FiberRecycling
2
+ This Ruby Gem offers a duck type for `Fiber` that will reuse old native fibers for a small performance gain. It will work as a drop in replacment for Ruby's natve `Fiber`, offering a small performance gain.
3
+
4
+ # Install
5
+ `gem install fiber_recycling`
6
+
7
+ Then simply `require 'fiber_recycling'` in your project.
8
+
9
+ # Example
10
+ `FiberRecycling::Fiber` can be used just like `::Fiber`.
11
+ ```ruby
12
+ fiber = FiberRecycling::Fiber.new do |a, b|
13
+ c = FiberRecycling::Fiber.yield(a)
14
+ d = FiberRecycling::Fiber.yield(c + 1)
15
+ d
16
+ end
17
+
18
+ fiber.resume(1, 2) # => 1
19
+ fiber.resume(3) # => 4
20
+ fiber.resume(5) # => 5
21
+ ```
22
+
23
+ ```ruby
24
+ fiber = FiberRecycling::Fiber.new do
25
+ FiberRecycling::Fiber.yield
26
+ end
27
+
28
+ fiber.resume # => nil
29
+ fiber.resume # => nil
30
+ fiber.resume # => FiberRecycling::FiberError, dead fiber called
31
+ ```
32
+
33
+ To integrate *FiberRecycling* into an existing project that relies on `Fiber` you can `include` `FiberRecycling::DuckTypes`.
34
+ ```ruby
35
+ module A
36
+ include FiberRecycling::DuckTypes
37
+
38
+ def self.a
39
+ fiber = Fiber.new do
40
+ Fiber.yield
41
+ end
42
+
43
+ fiber # => FiberRecycling::Fiber
44
+ fiber.resume # => nil
45
+ fiber.resume # => nil
46
+ fiber.resume # => FiberRecycling::FiberError, dead fiber resumed
47
+ end
48
+
49
+ end
50
+
51
+ A.a
52
+ ```
53
+
54
+ # How It Works
55
+ As fibers can only be resumed in the thread that they were created, a native fiber pool will be created on demand for each thread that a pool is needed. The native fibers in each pool also only be created on demand. When a new `FiberRecycling::Fiber` is created, it will create a new native fiber if none are available in thread's pool. The native fiber will only be returned to the pool when the `FiberRecycling::Fiber` has completed executing it's block (is in a dead state). As each pool is shared globally, possibly being accessed by multiple code bases that have no knowledge of each other, it is impossible to allow a code base to set a maximum pool size limit. One project may want a maximum size of 5 native fibers per thread while another may want 10, there is no way to satisfy both requests. As such *FiberRecycling* will put no constraint on the number of native fibers that can be created. Therefore, it is important to keep in mind that *FiberRecycling* will create as many native fibers as is simoustanly demanded and will not delete them until the thread gets garbage collected (if you are creating fibers in the main thread, this will obviously never happen). It is up to the developer of the code base to ensure that only a reasonable amount of `FiberRecycling::Fiber` will ever be alive simoustanly.
@@ -3,6 +3,6 @@ module FiberRecycling
3
3
 
4
4
  Fiber = Fiber
5
5
  FiberError = FiberError
6
-
6
+
7
7
  end
8
8
  end
@@ -12,6 +12,10 @@ module FiberRecycling
12
12
  Thread.current.thread_variable_get(:fiber_recycling__root_fiber)
13
13
  end
14
14
 
15
+ def self.root?
16
+ current == root
17
+ end
18
+
15
19
  def self.yield(*args)
16
20
  current.backend.class.yield(*args)
17
21
  end
@@ -47,5 +51,9 @@ module FiberRecycling
47
51
  @backend.transfer(*args)
48
52
  end
49
53
 
54
+ def variables
55
+ @backend.variables
56
+ end
57
+
50
58
  end
51
59
  end
@@ -8,8 +8,11 @@ module FiberRecycling
8
8
  return_value
9
9
  end
10
10
 
11
+ attr_reader :variables
12
+
11
13
  def initialize(fiber, block)
12
14
  @state = 'created'
15
+ @variables = {}
13
16
  @recycled_fiber = RecycledFiberPool.local.release_recycled_fiber
14
17
  @recycled_fiber.run { execute(fiber, block) }
15
18
  end
@@ -5,6 +5,12 @@ module FiberRecycling
5
5
  raise FiberError, "can't yield from root fiber"
6
6
  end
7
7
 
8
+ attr_reader :variables
9
+
10
+ def initialize
11
+ @variables = {}
12
+ end
13
+
8
14
  def alive?
9
15
  ::Fiber.root.alive?
10
16
  end
@@ -0,0 +1,21 @@
1
+ module FiberRecycling
2
+ module ThreadExtensions
3
+
4
+ def [](key)
5
+ if key == :fiber_recycling__fiber || Fiber.root?
6
+ super
7
+ else
8
+ Fiber.current.variables[key]
9
+ end
10
+ end
11
+
12
+ def []=(key, value)
13
+ if key == :fiber_recycling__fiber || Fiber.root?
14
+ super
15
+ else
16
+ Fiber.current.variables[key] = value
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -11,6 +11,8 @@ require 'fiber_recycling/normal_fiber_backend'
11
11
  require 'fiber_recycling/recycled_fiber'
12
12
  require 'fiber_recycling/recycled_fiber_pool'
13
13
  require 'fiber_recycling/root_fiber_backend'
14
+ require 'fiber_recycling/thread_extensions'
15
+ require_relative 'thread'
14
16
 
15
17
  module FiberRecycling
16
18
  end
data/lib/thread.rb ADDED
@@ -0,0 +1,4 @@
1
+ class Thread
2
+ prepend FiberRecycling::ThreadExtensions
3
+
4
+ end
@@ -0,0 +1,85 @@
1
+ require 'fiber_recycling'
2
+
3
+ RSpec.describe Thread do
4
+
5
+ context "when calling native method" do
6
+ it "should work" do
7
+ expect(Thread.current.alive?).to eql true
8
+ end
9
+ end
10
+
11
+ context "when in root FiberRecycling::Fiber" do
12
+
13
+ context "when setting a variable" do
14
+ it "should persist" do
15
+ Thread.current[:a] = 1
16
+ expect(Thread.current[:a]).to eql 1
17
+ end
18
+ end
19
+
20
+ context "when setting a variable" do
21
+ it "should not exist in FiberRecycling::Fiber" do
22
+ Thread.current[:a] = 1
23
+ fiber = FiberRecycling::Fiber.new do
24
+ Thread.current[:a]
25
+ end
26
+ expect(fiber.resume).to eql nil
27
+ end
28
+ end
29
+
30
+ context "when setting a variable" do
31
+ it "should should persist a new FiberRecycling::Fiber" do
32
+ Thread.current[:a] = 1
33
+ fiber = FiberRecycling::Fiber.new do
34
+ Thread.current[:a] = 2
35
+ end
36
+ fiber.resume
37
+ expect(Thread.current[:a]).to eql 1
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ context "when in non root FiberRecycling::Fiber" do
44
+
45
+ context "when getting a variable" do
46
+ it "should not exist outside FiberRecycling::Fiber" do
47
+ Thread.current[:a] = nil
48
+ fiber = FiberRecycling::Fiber.new do
49
+ Thread.current[:a] = 1
50
+ end
51
+ fiber.resume
52
+ expect(Thread.current[:a]).to eql nil
53
+ end
54
+ end
55
+
56
+ context "when setting a variable" do
57
+ it "should persist a yield" do
58
+ Thread.current[:a] = nil
59
+ fiber = FiberRecycling::Fiber.new do
60
+ Thread.current[:a] = 1
61
+ FiberRecycling::Fiber.yield
62
+ Thread.current[:a]
63
+ end
64
+ fiber.resume
65
+ Thread.current[:a] = 2
66
+ expect(fiber.resume).to eql 1
67
+ end
68
+ end
69
+
70
+ context "when setting a variable" do
71
+ it "should not leak to next fiber" do
72
+ Thread.current[:a] = nil
73
+ fiber1 = FiberRecycling::Fiber.new do
74
+ Thread.current[:a] = 1
75
+ end
76
+ fiber1.resume
77
+ fiber2 = FiberRecycling::Fiber.new do
78
+ Thread.current[:a]
79
+ end
80
+ expect(fiber2.resume).to eql nil
81
+ end
82
+ end
83
+
84
+ end
85
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiber_recycling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Fors
@@ -43,9 +43,12 @@ files:
43
43
  - lib/fiber_recycling/recycled_fiber.rb
44
44
  - lib/fiber_recycling/recycled_fiber_pool.rb
45
45
  - lib/fiber_recycling/root_fiber_backend.rb
46
+ - lib/fiber_recycling/thread_extensions.rb
47
+ - lib/thread.rb
46
48
  - spec/duck_types_spec.rb
47
49
  - spec/fiber_spec.rb
48
50
  - spec/spec_helper.rb
51
+ - spec/thread_spec.rb
49
52
  homepage: https://github.com/robfors/fiber_recycling
50
53
  licenses:
51
54
  - MIT