Forking and Threads
Paul Robinson
paul.robinson at businesscollaborator.com
Thu Feb 8 08:13:56 EST 2001
OK, before I start, I realise that threading and forking are not
necessarily well known for playing well with each other. But given that,
and assuming that this is the road I have chosen to go down can anyone
explain why the attached program (also available at:
http://cobweb.quantisci.co.uk/pub/english.cgi/d10030658/forkingtest2.py
) will run happily for several minutes (upto about 10mins so far) and
then just sit there with the main process running with as much CPU time
as the OS will give it!
This is the "distilled down" version of the problem that I'm seeing in a
much larger application.
I've only tested this on:
Python 1.5.2
Red Hat Linux release 6.2 (Zoot)
Kernel 2.2.14-5.0smp on a 2-processor i686
and would very interested in how (and if) it performs on other operating
systems - obviously only those with both threading and forking need
apply.
I find that "watch -n 1 "pstree -c -p -a <user name> | grep python |
grep -v grep"" gives a overview of the running of the program as you can
see the child processes appearing and disappearing.
A large number of child processes and a short run time for the children
seems to cause the crash most quickly. These parameters can be set with
-MC (MAX_CHILDREN) and -MS (MAX_SECONDS the child will wait for).
forkingtest2.py -MC 20 -MS 3 crashes after a while on my dual 350MHz
PII.
Any insight into this behaviour would be gratefully appreciated.
Paul Robinson
Business Collaborator Development Manager
Enviros Software Solutions
WWW: http://www.businesscollaborator.com
-------------- next part --------------
#!/usr/bin/python
import os, sys
import marshal
from threading import Thread, currentThread
from time import sleep, time
from random import choice, seed
from string import atoi
CHILD = 0
MAX_CHILDREN = 5
MAX_SLEEP = 5
def log(*args):
print '\t'*CHILD, os.getpid(),' : ', currentThread(), \
' : ', reduce(lambda x, y: x + ' '+ y, map(str,args))
def processLoop():
children = []
while 1:
while len(children) < MAX_CHILDREN:
pid = os.fork()
if pid:
#parent
children.append(pid)
else:
#child
try:
global CHILD
CHILD = CHILD + 1
#Do stuff
seed(time())
pause = choice(range(1,MAX_SLEEP))
log('Sleeping', pause)
sleep(pause)
log('Exitting')
finally:
os._exit(0)
else:
log('Too many children')
sleep(3)
# Wait on children
for i in range(len(children)-1, -1, -1):
# Call waitpid (os.WNOHANG - non-blocking)
status = os.waitpid(children[i], os.WNOHANG)
if status[0] > 0:
# Child has been "deaded"
del children[i]
if __name__ == '__main__':
try:
i = sys.argv.index('-MC')
global MAX_CHILDREN
MAX_CHILDREN = atoi(sys.argv[i+1])
except:
pass
print 'Set MAX_CHILDREN to', MAX_CHILDREN, ' - use "-MC n" to change'
try:
i = sys.argv.index('-MS')
global MAX_SLEEP
MAX_SLEEP = atoi(sys.argv[i+1])
MAX_SLEEP = ((MAX_SLEEP >= 2) and MAX_SLEEP) or 2
except:
pass
print 'Set MAX_SLEEP to', MAX_SLEEP, ' - use "-MS m" to change (where m >= 2)'
pl = Thread(target=processLoop, name='processLoop')
pl.start()
currentThread().setName('Main Loop')
f = open('/tmp/temp','a')
while 1:
log('Looping')
sleep(5)
More information about the Python-list
mailing list