Class: Forkner

Inherits:
Object
  • Object
show all
Defined in:
lib/forkner.rb

Overview

Forkner

Constant Summary collapse

VERSION =

Version 1.1

'1.1'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max) ⇒ Forkner

Creates a new Forkner object. The single parameter is the maximum number of child processes to run at once. So, for example, the following code creates a Forkner object that will allow up to five child processes at once.

forkner = Forkner.new(5)


64
65
66
67
68
69
# File 'lib/forkner.rb', line 64

def initialize(max)
  @max = max
  @children = {}
  @tmp_dir = '/tmp'
  @reaper = nil
end

Instance Attribute Details

#maxObject

The maximum number of child processes to run at once.



11
12
13
# File 'lib/forkner.rb', line 11

def max
  @max
end

#tmp_dirObject

Temporary directory for storing information from child processes. Defaults to /tmp.



15
16
17
# File 'lib/forkner.rb', line 15

def tmp_dir
  @tmp_dir
end

Class Method Details

.container(max) {|forkner| ... } ⇒ Object

container is probably the easiest way to use Forkner. Run all the code that will have child processes inside a container block. The single parameter for container is the maximum number of child processes to allow. After the container block, Forkner waits for all remaining child processes to exit.

So, for example, this code loops 100 times, but will not fork more than five children at a time:

Forkner.container(5) do |forkner|
    100.times do
        forkner.child do
            # do stuff in the child process
        end
    end
end

Yields:

  • (forkner)


43
44
45
46
47
# File 'lib/forkner.rb', line 43

def self.container(max)
  forkner = Forkner.new(max)
  yield forkner
  forkner.wait_all
end

Instance Method Details

#childObject

Runs a child process. If there are already the maximum number of children running then this method waits until one of them exits. The last line of the block is information that can be stored in JSON, and if you have defined a reaper block, then that information will be conveyed back to the parent process.

For example, this child process generates a random number and a timestamp. The last line of the block is a hash that will be sent back to the parent process.

forkner.child do
    myrand = rand()
    timestamp = Time.now
    {'myrand'=>myrand, 'timestamp'=>timestamp}
end


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/forkner.rb', line 95

def child
  # init
  json_path = nil
  
  # transfer file
  if @reaper
    json_path = Random.rand().to_s
    json_path = json_path.sub(/\A.*\./mu, '')
    json_path = @tmp_dir + '/' + json_path
  end
  
  # wait until we have a space for a process
  waiter @max - 1
  
  # parent process
  if new_child_pid = Process.fork()
    # set child record
    child = @children[new_child_pid] = {}
    
    # file handle
    if @reaper
      child['json_path'] = json_path
    end
    
    # return true
    return true
  
  # child process
  else
    # yield if necessary
    if block_given?
      rv = yield()
      
      # save to json file if necessary
      if json_path
        File.write json_path, JSON.generate(rv)
      end
      
      # exit child process
      exit
    end
    
    # always return false
    return false
  end
end

#reaper(&block) ⇒ Object

Defines the block to run when a child process finishes. The single param passed to the block is a hash or array of information from the child process. For example, if the child process returns a hash of information, you might display it like this:

forkner.reaper() do |rv|
    puts '-----'
    puts rv['myrand']
    puts rv['timestamp']
end


161
162
163
# File 'lib/forkner.rb', line 161

def reaper(&block)
  @reaper = block
end

#wait_allObject Also known as: waitall

Waits for all child processes to finish. You don’t need to call this method if you’re using Forkner.container.



176
177
178
# File 'lib/forkner.rb', line 176

def wait_all
  waiter 0
end