Created
October 24, 2009 07:31
-
-
Save axgle/217427 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=begin rdoc | |
=Introduction | |
ForkManager is a very simple Class for managing the forking of | |
processes in a controlled manner. ForkManager allows for the limiting | |
of concurrent child processes to a number specified by the user. | |
Copyright (c) 2006 Dustin Spinhirne - http://spinhirne.com | |
Licensed under the same terms as Ruby, No Warranty is provided. | |
====Example 1: | |
#!/usr/bin/ruby | |
# A simple ForkManager demo script | |
require 'rubygems' | |
require_gem 'fork_manager' | |
puts "PARENT PID #{Process.pid}" | |
fm = ForkManager.new(5) | |
# loop 20 times, each time fork a child and print that child's pid | |
# sleep for 3 seconds so that there is time to see how processes are limited. | |
statuses = fm.manage do | |
20.times do | |
fm.fork do | |
puts " CHILD PID #{Process.pid}" | |
sleep 3 | |
end | |
end | |
end | |
puts "Finished" | |
====Example 2: | |
#!/usr/bin/ruby | |
# A simple network ping sweep script. | |
require 'ping' | |
require 'rubygems' | |
require_gem 'fork_manager' | |
require_gem 'netaddr' | |
blocks = ['10.4.0.0/27', '10.4.0.32/27','10.4.0.64/27','10.4.0.96/27',] | |
fm = ForkManager.new(2) | |
# for each cidr block, ping sweep & return addresses that are up. | |
# limit to (2) forked processes | |
fm.manage do | |
blocks.each do |x| | |
cidr = NetAddr::CIDR.create(x) | |
fm.fork do | |
puts "forking for #{x}" | |
cidr.enumerate.each do |ip| | |
if ( Ping.pingecho(ip,1) ) | |
puts "#{ip} is up" | |
else | |
puts "#{ip} is down" | |
end | |
end | |
end | |
end | |
end | |
puts "Finished" | |
=end | |
class ForkManager | |
# Current limit of concurrent child processes | |
attr_reader :max_children | |
# Set the limit of concurrent child processes (Integer) | |
attr_writer :max_children | |
#===Synopsis | |
# Create a ForkManager object. | |
# | |
# fm = Forkmanager.new | |
# fm = Forkmanager.new(2) | |
# | |
#===Arguments: | |
#* Maximum number of child processes to fork at a given time - Integer (optional) | |
# | |
def initialize(max_children=20) | |
raise "Integer expected, but #{max_children.class} provided for argument: max_children." if (!max_children.kind_of?(Integer)) | |
@max_children = max_children | |
@child_count = 0 | |
@managed = false | |
end | |
#===Synopsis | |
#Used to perform the actual fork. Code called from within this | |
#block will be executed from within a forked child process. | |
# | |
# fm.manage do | |
# fm.fork do | |
# puts Process.pid | |
# end | |
# end | |
# | |
#===Arguments: | |
#* none | |
# | |
#===Returns: | |
#* Process ID of child process | |
# | |
def fork() | |
raise "ForkManager.fork may only be called from " + | |
"within ForkManager.manage." if !@managed | |
if (@child_count >= @max_children) | |
Process.wait | |
@child_count -= 1 | |
end | |
child = Process.fork {yield} | |
@child_count += 1 | |
return(child) | |
end | |
#===Synopsis | |
#Top level container used for managing child processes. | |
#ForkManager.fork should only be called from | |
#within the confines of this container. | |
# | |
# fm.manage do | |
# fm.fork{} | |
# end | |
# | |
#===Arguments: | |
#* none | |
# | |
#===Returns: | |
#* Array of pid/status pairs (see Process.waitall for more information) | |
# | |
def manage() | |
@managed = true | |
yield | |
processes = Process.waitall | |
@managed = false | |
return(processes) | |
end | |
end | |
__END__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment