Class: Forkner

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

Overview

Forkner

Constant Summary collapse

VERSION =

version 1.2

'1.2'

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)


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

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)


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

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


94
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
# File 'lib/forkner.rb', line 94

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


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

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.



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

def wait_all
	waiter 0
end