The following program demonstrates the use of os.fork() and os.wait() in Python. The program forks several processes, each of which counts to a number. The parent process waits for each child process to end, and prints that process's return value.
#!/usr/bin/env python from optparse import OptionParser import os import sys import time def worker(count): for i in range(count): time.sleep(1) print '[%s] => %s' % (os.getpid(), i) def boss(num_workers, count): child_pids = [] for i in range(num_workers): pid = os.fork() if pid == 0: worker(count) os._exit(i) else: child_pids.append(pid) for pid in child_pids: pid, status = os.waitpid(pid, 0) if os.WIFEXITED(status): print 'parent: child with pid %d exited with value %d' % \ (pid, os.WEXITSTATUS(status)) if __name__ == '__main__': usage = '''usage: %prog [options] Demonstrate fork and wait system calls.''' version = '%prog 1.0' parser = OptionParser(usage=usage, version=version) parser.add_option('-n', '--num-workers', dest='num_workers', type='int', default=5, help='number of child worker processes to fork (default=5)') parser.add_option('-c', '--toil-count', dest='toil_count', type='int', default=10, help='the number each worker process must count to (default=10)') (options, args) = parser.parse_args() boss(options.num_workers, options.toil_count)
A sample output of running the program with seven worker processes, each of which counts to three, is shown below.
$ ./forkwait.py -n 7 -c 3 [692] => 0 [695] => 0 [694] => 0 [693] => 0 [697] => 0 [696] => 0 [698] => 0 [695] => 1 [692] => 1 [693] => 1 [697] => 1 [698] => 1 [694] => 1 [696] => 1 [695] => 2 [692] => 2 [697] => 2 [693] => 2 [698] => 2 [694] => 2 [696] => 2 parent: child with pid 692 exited with value 0 parent: child with pid 693 exited with value 1 parent: child with pid 694 exited with value 2 parent: child with pid 695 exited with value 3 parent: child with pid 696 exited with value 4 parent: child with pid 697 exited with value 5 parent: child with pid 698 exited with value 6
Our next program is a bit more interesting. In this program, the user species a list of webpages to download. For each webpage, the program forks a new process and uses os.execlp() to execute wget.
#!/usr/bin/env python from optparse import OptionParser import os import sys import time import urlparse def wget(webpages): child_pids = [] for webpage in webpages: pid = os.fork() if pid == 0: # generate output name to prevent many duplicate index.html's o = urlparse.urlparse(webpage) output = o.netloc + o.path output = output.replace(os.path.sep, '__') print '[*] saving %s to %s' % (webpage, output) os.execlp('wget', 'wget', '--quiet', '--output-document', output, webpage) assert False, 'error starting wget' else: child_pids.append(pid) for pid in child_pids: pid, status = os.waitpid(pid, 0) if os.WIFEXITED(status): print 'parent: child with pid %d exited with value %d' % \ (pid, os.WEXITSTATUS(status)) if __name__ == '__main__': usage = '''usage: %prog [url ...] Retrieve one or more webpages. ''' version = '%prog 1.0' parser = OptionParser(usage=usage, version=version) (options, args) = parser.parse_args() wget(args)
In the sample run below, we attempt to download the homepage's of smherwig.org, lua.org, and the nonexistent, invalid URL, foo.
$ ./forkwget.py http://smherwig.org/index.html http://lua.org foo [*] saving http://smherwig.org/index.html to smherwig.org__index.html [*] saving http://lua.org to lua.org [*] saving foo to foo parent: child with pid 1153 exited with value 0 parent: child with pid 1154 exited with value 0 parent: child with pid 1155 exited with value 4
No comments:
Post a Comment