fiber_pool 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fiber_pool.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # What is this ?
2
+
3
+ It is a basic implementation of a fiber pool extracted for my projects,
4
+ I need a pool in many project and I am tired of having to reimplement it
5
+ in every project so here goes my gem !
6
+
7
+ My implementation is based on the neverblock one but I added some changes of
8
+ my own over time.
9
+
10
+ # Features
11
+
12
+ - Constant count of fibers with a queue (I am sure you would have never guessed ;) )
13
+ - should any uncaught error occur in one fiber of the poll then another one
14
+ will be spawned to keep the pool state (you should not let errors uncaught but
15
+ my experience clearly shows me that it can happen and it can trigger really weird bug
16
+ if your poll runs out of fibers)
17
+
18
+ # Usage
19
+
20
+ I use it mainly with EventMachine but it is in no way required, that said it may not be
21
+ of much use without, I did not gave it much thoughts :)
22
+
23
+ # create a pool contained 10 fibers
24
+ pool = FiberPool.new(10)
25
+
26
+ # and spawn a job
27
+ # if a fiber is free it will be executed immediatly
28
+ # otherwise the block is queued
29
+ pool.spawn{ do_something() }
30
+
31
+
32
+ # Warning
33
+
34
+ If you use this You should already be aware of how fibers work, If not go read about them
35
+ and keep in mind that when a Fiber is running nothing else will, they are like threads but
36
+ you are responsible for the scheduling.
37
+
38
+
39
+ # Supported Runtimes
40
+
41
+ - MRI 1.8.6+ (in ruby 1.8 the thread based fiber implementation will be used)
42
+ - Rubinius 1.2.2+ (fiber support is still experimental so be careful what you do this it here)
43
+
44
+
45
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fiber_pool/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fiber_pool"
7
+ s.version = FiberPool::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Julien Ammmous"]
10
+ s.email = []
11
+ s.homepage = ""
12
+ s.summary = %q{Fiber Pool Implementation}
13
+ s.description = %q{A General purpose fiber pool}
14
+
15
+ s.rubyforge_project = "fiber_pool"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+
23
+ end
@@ -0,0 +1,83 @@
1
+ # Poor Man's Fiber (API compatible Thread based Fiber implementation for Ruby 1.8)
2
+ # (c) 2008 Aman Gupta (tmm1)
3
+
4
+ unless defined? Fiber
5
+ $:.unshift File.expand_path(File.dirname(__FILE__)) + '/compat'
6
+ require 'thread'
7
+
8
+ class FiberError < StandardError; end
9
+
10
+ class Fiber
11
+ def initialize
12
+ raise ArgumentError, 'new Fiber requires a block' unless block_given?
13
+
14
+ @yield = Queue.new
15
+ @resume = Queue.new
16
+
17
+ @thread = Thread.new{ @yield.push [yield(*@resume.pop)] }
18
+ @thread.abort_on_exception = true
19
+ @thread[:fiber] = self
20
+ end
21
+ attr_reader :thread
22
+
23
+ def resume *args
24
+ raise FiberError, 'dead fiber called' unless @thread.alive?
25
+ @resume.push(args)
26
+ result = @yield.pop
27
+ result.size > 1 ? result : result.first
28
+ end
29
+
30
+ def yield *args
31
+ @yield.push(args)
32
+ result = @resume.pop
33
+ result.size > 1 ? result : result.first
34
+ end
35
+
36
+ def alive?
37
+ @thread.alive?
38
+ end
39
+
40
+ def self.yield *args
41
+ if fiber = Thread.current[:fiber]
42
+ fiber.yield(*args)
43
+ else
44
+ raise FiberError, 'not inside a fiber'
45
+ end
46
+ end
47
+
48
+ def self.current
49
+ if Thread.current == Thread.main
50
+ return Thread.main[:fiber] ||= RootFiber.new
51
+ end
52
+
53
+ Thread.current[:fiber] or raise FiberError, 'not inside a fiber'
54
+ end
55
+
56
+ def inspect
57
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
58
+ end
59
+ end
60
+
61
+ class RootFiber < Fiber
62
+ def initialize
63
+ # XXX: what is a root fiber anyway?
64
+ end
65
+
66
+ def self.yield *args
67
+ raise FiberError, "can't yield from root fiber"
68
+ end
69
+ end
70
+ end
71
+
72
+ if __FILE__ == $0
73
+ f = Fiber.new{ |sym|
74
+ p(sym)
75
+ puts 'hi'
76
+ p(Fiber.yield 1)
77
+ puts 'bye'
78
+ :end
79
+ }
80
+ p(f.resume :begin)
81
+ p(f.resume 2)
82
+ end
83
+
@@ -0,0 +1,95 @@
1
+ begin
2
+ require 'fiber'
3
+ if defined?(Rubinius::Fiber)
4
+ Fiber = Rubinius::Fiber
5
+ end
6
+
7
+ rescue LoadError
8
+ require File.expand_path('../fiber18', __FILE__)
9
+ end
10
+
11
+ class FiberPool
12
+ # Prepare a list of fibers that are able to run different blocks of code
13
+ # every time. Once a fiber is done with its block, it attempts to fetch
14
+ # another one from the queue
15
+ def initialize(count = 100)
16
+ @fibers,@busy_fibers,@queue = [],{},[]
17
+
18
+ count.times do |i|
19
+ add_fiber()
20
+ end
21
+ end
22
+
23
+ def add_fiber
24
+ fiber = Fiber.new do |block|
25
+ loop do
26
+ block.call
27
+ unless @queue.empty?
28
+ block = @queue.shift
29
+ else
30
+ @busy_fibers.delete(Fiber.current.object_id)
31
+ @fibers.unshift Fiber.current
32
+ block = Fiber.yield
33
+ end
34
+ end
35
+ end
36
+
37
+ @fibers << fiber
38
+ fiber
39
+ end
40
+
41
+ # If there is an available fiber use it, otherwise, leave it to linger
42
+ # in a queue
43
+ def spawn(&block)
44
+ # resurrect dead fibers
45
+ @busy_fibers.values.reject(&:alive?).each do |f|
46
+ @busy_fibers.delete(f.object_id)
47
+ add_fiber()
48
+ end
49
+
50
+ if fiber = @fibers.shift
51
+ @busy_fibers[fiber.object_id] = fiber
52
+ fiber.resume(block)
53
+ else
54
+ @queue << block
55
+ end
56
+
57
+ fiber
58
+ end
59
+
60
+ end
61
+
62
+
63
+ if $0 == __FILE__
64
+ pool = FiberPool.new(2)
65
+ f1 = pool.spawn do
66
+ puts "1"
67
+ puts Fiber.yield
68
+ end
69
+
70
+ begin
71
+ pool.spawn do
72
+ puts "2"
73
+ f1.resume(42)
74
+ raise 'arggggg'
75
+ end
76
+ rescue => err
77
+ p err.inspect
78
+ end
79
+
80
+ begin
81
+ pool.spawn do
82
+ raise 'arggggg 222'
83
+ end
84
+
85
+ rescue => err
86
+ p err.inspect
87
+ end
88
+
89
+
90
+ pool.spawn do
91
+ puts "I am alive !!!"
92
+ end
93
+
94
+ end
95
+
@@ -0,0 +1,3 @@
1
+ module FiberPool
2
+ VERSION = "0.9.0"
3
+ end
data/lib/fiber_pool.rb ADDED
@@ -0,0 +1,7 @@
1
+ module FiberPool
2
+ def self.require_lib(path)
3
+ require File.expand_path("../#{path}", __FILE__)
4
+ end
5
+
6
+ require_lib("fiber_pool/version")
7
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fiber_pool
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.9.0
6
+ platform: ruby
7
+ authors:
8
+ - Julien Ammmous
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-24 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: A General purpose fiber pool
17
+ email: []
18
+
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - .gitignore
27
+ - Gemfile
28
+ - README.md
29
+ - Rakefile
30
+ - fiber_pool.gemspec
31
+ - lib/fiber_pool.rb
32
+ - lib/fiber_pool/fiber18.rb
33
+ - lib/fiber_pool/pool.rb
34
+ - lib/fiber_pool/version.rb
35
+ homepage: ""
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ requirements: []
56
+
57
+ rubyforge_project: fiber_pool
58
+ rubygems_version: 1.7.2
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Fiber Pool Implementation
62
+ test_files: []
63
+
64
+ has_rdoc: