fiber_pool 0.9.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.
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: