Thread scheduling

Jack Orenstein jao at geophile.com
Sat Feb 26 17:28:25 EST 2005


I am using Python 2.2.2 on RH9, and just starting to work with Python
threads.

I started using the threading module and found that 10-20% of the runs
of my test program would hang. I developed smaller and smaller test
cases, finally arriving at the program at the end of this message,
which uses the thread module, not threading. This program seems to
point to problems in Python thread scheduling.

The program is invoked like this:

     python threadtest.py THREADS COUNT

THREADS is the number of threads created. Each thread contains a loop
that runs COUNT times, and all threads increment a counter. (The
counter is incremented without locking -- I expect to see a final
count of less than THREADS * COUNT.)

Running with THREADS = 2 and COUNT = 100000, most of the time, the
program runs to completion. About 20% of the time however, I see one
thread finish, but the other thread never resumes.

Here is output from a run that completes normally:

     [jao at black]$ python threadtest.py 2 100000
     nThreads: 2
     nCycles: 100000
     thread 1: started
     thread 1: i = 0, counter = 1
     thread 2: started
     thread 2: i = 0, counter = 2691
     thread 1: i = 10000, counter = 13496
     thread 2: i = 10000, counter = 22526
     thread 1: i = 20000, counter = 27120
     thread 2: i = 20000, counter = 40365
     thread 1: i = 30000, counter = 41264
     thread 1: i = 40000, counter = 55922
     thread 2: i = 30000, counter = 58416
     thread 2: i = 40000, counter = 72647
     thread 1: i = 50000, counter = 74602
     thread 1: i = 60000, counter = 88468
     thread 2: i = 50000, counter = 99319
     thread 1: i = 70000, counter = 110144
     thread 2: i = 60000, counter = 110564
     thread 2: i = 70000, counter = 125306
     thread 1: i = 80000, counter = 129252
     Still waiting, done = 0
     thread 2: i = 80000, counter = 141375
     thread 1: i = 90000, counter = 147459
     thread 2: i = 90000, counter = 155268
     thread 1: leaving
     thread 2: leaving
     Still waiting, done = 2
     All threads have finished, counter = 168322

Here is output from a run that hangs. I killed the process using
ctrl-c.

     [jao at black]$ python threadtest.py 2 100000
     nThreads: 2
     nCycles: 100000
     thread 1: started
     thread 1: i = 0, counter = 1
     thread 2: started
     thread 2: i = 0, counter = 990
     thread 1: i = 10000, counter = 11812
     thread 2: i = 10000, counter = 13580
     thread 1: i = 20000, counter = 19127
     thread 2: i = 20000, counter = 25395
     thread 1: i = 30000, counter = 31457
     thread 1: i = 40000, counter = 44033
     thread 2: i = 30000, counter = 48563
     thread 1: i = 50000, counter = 55131
     thread 1: i = 60000, counter = 65291
     thread 1: i = 70000, counter = 78145
     thread 2: i = 40000, counter = 82715
     thread 1: i = 80000, counter = 92073
     thread 2: i = 50000, counter = 101784
     thread 1: i = 90000, counter = 104294
     thread 2: i = 60000, counter = 112866
     Still waiting, done = 0
     thread 1: leaving
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Still waiting, done = 1
     Traceback (most recent call last):
       File "threadtest.py", line 26, in ?
         time.sleep(1)
     KeyboardInterrupt
     [jao at black osh]$

In this case, thread 1 finishes but thread 2 never runs again. Is
this a known problem? Any ideas for workarounds? Are threads widely
used in Python?

Jack Orenstein



# threadtest.py

import sys
import thread
import time

nThreads = int(sys.argv[1])
nCycles = int(sys.argv[2])
print 'nThreads: %d' % nThreads
print 'nCycles: %d' % nCycles
counter = 0
done = 0

def run(id):
     global done
     print 'thread %d: started' % id
     global counter
     for i in range(nCycles):
         counter += 1
         if i % 10000 == 0:
             print 'thread %d: i = %d, counter = %d' % (id, i, counter)
     print 'thread %d: leaving' % id
     done += 1

for i in range(nThreads):
     thread.start_new_thread(run, (i + 1,))
while done < nThreads:
     time.sleep(1)
     print 'Still waiting, done = %d' % done
print 'All threads have finished, counter = %d' % counter



More information about the Python-list mailing list