Skip to content

Instantly share code, notes, and snippets.

@axgle
Created October 24, 2009 07:31
Show Gist options
  • Save axgle/217427 to your computer and use it in GitHub Desktop.
Save axgle/217427 to your computer and use it in GitHub Desktop.
=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