celluloid-task-pooledfiber 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +36 -0
- data/Rakefile +8 -0
- data/celluloid-task-pooledfiber.gemspec +20 -0
- data/lib/celluloid/task/pooled_fiber.rb +1 -0
- data/lib/celluloid/task_pooled_fiber.rb +21 -0
- data/lib/celluloid/util/fiber_pool.rb +95 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce7677f3d306f7ab9e1fd473f2a45386a21ec953
|
4
|
+
data.tar.gz: 69a81b51fb510f73ffc68137c5f6fea66afdaa3e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 040302514e06883c48056eb92d5e074453ba992e2deb25fb961da5de9d37adf97b084fce49953497afe70e544b10a523d52b198b2cc9945e8021592bf8335dc3
|
7
|
+
data.tar.gz: c81f30f0a4aee9ba1b3bf9ea6384f02358f89bd3342c87c1f57f7e19d80a455c8d1899cd0e1bbbd566cea8f54ddfb9356650b0331e2ebe3b111d653713863a88
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Chris Heald
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Celluloid::TaskPooledFiber
|
2
|
+
|
3
|
+
[](https://travis-ci.org/celluloid/celluloid-task-pooledfiber)
|
4
|
+
|
5
|
+
Provides a Task implementation which reuses a pool of fibers to run tasks. This improves Celluloid's performance.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'celluloid-task-pooledfiber'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install celluloid-task-pooledfiber
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
In your application, before starting Celluloid:
|
24
|
+
|
25
|
+
require 'celluloid/task_pooled_fiber'
|
26
|
+
Celluloid.task_class = Celluloid::TaskPooledFiber
|
27
|
+
|
28
|
+
That's it.
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
1. Fork it ( https://github.com/celluloid/celluloid-task-pooledfiber/fork )
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
36
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "celluloid-task-pooledfiber"
|
7
|
+
spec.version = "0.1.0"
|
8
|
+
spec.authors = ["Chris Heald"]
|
9
|
+
spec.email = ["cheald@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{An alternate Task implementation for Celluloid which improves performance by reusing a pool of fibers to run tasks}
|
12
|
+
spec.description = %q{An alternate Task implementation for Celluloid which improves performance by reusing a pool of fibers to run tasks}
|
13
|
+
spec.homepage = "http://github.com/celluloid/celluloid-task-pooledfiber"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_dependency "celluloid", "~> 0.16"
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "../task_pooled_fiber.rb"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Celluloid
|
5
|
+
require_relative './util/fiber_pool'
|
6
|
+
|
7
|
+
class TaskPooledFiber < TaskFiber
|
8
|
+
def self.fiber_pool
|
9
|
+
@fiber_pool ||= Util::FiberPool.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(&block)
|
13
|
+
queue = Thread.current[:celluloid_queue]
|
14
|
+
@fiber = TaskPooledFiber.fiber_pool.acquire do
|
15
|
+
Thread.current[:celluloid_role] = :actor
|
16
|
+
Thread.current[:celluloid_queue] = queue
|
17
|
+
block.call
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Celluloid
|
2
|
+
module Util
|
3
|
+
class FiberPool
|
4
|
+
attr_accessor :stats
|
5
|
+
|
6
|
+
def initialize(trim_size = 64)
|
7
|
+
@trim_size = trim_size
|
8
|
+
@pool = {}
|
9
|
+
@stats = { created: 0, acquired: 0, trimmed: 0, sweep_counter: 0, terminated: 0, terminated_threads: 0, sweeps: 0 }
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def acquire(&block)
|
14
|
+
trim
|
15
|
+
sweep
|
16
|
+
@stats[:acquired] += 1
|
17
|
+
fiber = fiber_pool.shift || create_fiber
|
18
|
+
fiber.resume(block)
|
19
|
+
fiber
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def create_fiber
|
25
|
+
pool = fiber_pool
|
26
|
+
@stats[:created] += 1
|
27
|
+
Fiber.new do |blk|
|
28
|
+
loop do
|
29
|
+
# At this point, we have a pooled fiber ready for Celluloid to call #resume on.
|
30
|
+
Fiber.yield
|
31
|
+
|
32
|
+
# Once Celluloid resumes the fiber, we need to execute the block the task was
|
33
|
+
# created with. This may call suspend/resume; that's fine.
|
34
|
+
blk.call
|
35
|
+
|
36
|
+
# Once Celluloid completes the task, we release this Fiber back to the pool
|
37
|
+
pool << Fiber.current
|
38
|
+
|
39
|
+
# ...and yield for the next #acquire call.
|
40
|
+
blk = Fiber.yield
|
41
|
+
break if blk == :terminate
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# If the fiber pool has grown too much, shift off and discard
|
47
|
+
# extra fibers so they may be GC'd. This isn't ideal, but it
|
48
|
+
# should guard against runaway resource consumption.
|
49
|
+
def trim
|
50
|
+
pool = fiber_pool
|
51
|
+
while pool.length > @trim_size
|
52
|
+
@stats[:trimmed] += 1
|
53
|
+
pool.shift.resume(:terminate)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def sweep
|
58
|
+
@mutex.synchronize do
|
59
|
+
@stats[:sweep_counter] += 1
|
60
|
+
if @stats[:sweep_counter] > 10_000
|
61
|
+
alive = []
|
62
|
+
Thread.list.each do |thread|
|
63
|
+
alive << thread.object_id if thread.alive? && @pool.key?(thread.object_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
(@pool.keys - alive).each do |thread_id|
|
67
|
+
@pool[thread_id].each do |_fiber|
|
68
|
+
@stats[:terminated] += 1
|
69
|
+
# We can't resume the fiber here because we might resume cross-thread
|
70
|
+
# TODO: How do we deal with alive fibers in a dead thread?
|
71
|
+
# fiber.resume(:terminate)
|
72
|
+
end
|
73
|
+
@stats[:terminated_threads] += 1
|
74
|
+
@pool.delete thread_id
|
75
|
+
end
|
76
|
+
@stats[:sweep_counter] = 0
|
77
|
+
@stats[:sweeps] += 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Fiber pool for this thread. Fibers can't cross threads, so we have to maintain a
|
83
|
+
# pool per thread.
|
84
|
+
#
|
85
|
+
# We keep our pool in an instance variable rather than in thread locals so that we
|
86
|
+
# can sweep out old Fibers from dead threads. This keeps live Fiber instances in
|
87
|
+
# a thread local from keeping the thread from being GC'd.
|
88
|
+
def fiber_pool
|
89
|
+
@mutex.synchronize do
|
90
|
+
@pool[Thread.current.object_id] ||= []
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: celluloid-task-pooledfiber
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Heald
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: celluloid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.16'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.16'
|
27
|
+
description: An alternate Task implementation for Celluloid which improves performance
|
28
|
+
by reusing a pool of fibers to run tasks
|
29
|
+
email:
|
30
|
+
- cheald@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- .gitignore
|
36
|
+
- .rspec
|
37
|
+
- .travis.yml
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE.txt
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- celluloid-task-pooledfiber.gemspec
|
43
|
+
- lib/celluloid/task/pooled_fiber.rb
|
44
|
+
- lib/celluloid/task_pooled_fiber.rb
|
45
|
+
- lib/celluloid/util/fiber_pool.rb
|
46
|
+
homepage: http://github.com/celluloid/celluloid-task-pooledfiber
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata: {}
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 2.4.6
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: An alternate Task implementation for Celluloid which improves performance
|
70
|
+
by reusing a pool of fibers to run tasks
|
71
|
+
test_files: []
|