[Python-Dev] GIL behaviour under Windows (original) (raw)

Sturla Molden sturla at molden.no
Thu Oct 22 05:09:44 CEST 2009


Sturla Molden skrev:

However, David Beazley is not talking about Windows. Since the GIL is apparently not a mutex on Windows, it could behave differently. So I wrote a small script that contructs a GIL battle, and record how often a check-interval results in a thread-switch or not. For monitoring check intervals, I used a small C extension to read PyTicker from ceval.c. It is not declared static so I could easily hack into it.

Anyway, if anyone wants to run a GIL battle, here is the code I used.

If it turns out the GIL is far worse with pthreads, as it is implemented with a mutex, it might be a good idea to reimplement it with an event object as it is on Windows.

Sturla Molden


In python:

from giltest import * from time import clock import threading import sys

def thread(rank, battle, start):

while not start.isSet():
    if rank == 0:
        start.set()

try:
    while 1:
        battle.record(rank)
except:
    pass   

if name == 'main':

sys.setcheckinterval(1000)

print "check interval = %d" % sys.getcheckinterval()

for nthreads  in range(1,7):

    start = threading.Event()
    battle = GIL_Battle(100000)
    threads = [threading.Thread(target=thread, args=(i,battle,start))
                for i in range(1,nthreads)]
    for t in threads:
        t.setDaemon(True)
        t.start()

    thread(0, battle, start)
    for t in threads: t.join()
                                   
    s,m = battle.report()
   
    print "nthreads=%d, swiched=%d, missed=%d" % (nthreads, s, m)

In Cython or Pyrex:

from exceptions import Exception

cdef extern from *: ctypedef int vint "volatile int" vint _Py_Ticker

class StopBattle(Exception): pass

cdef class GIL_Battle:

""" tests the fairness of the GIL """

cdef vint prev_tick, prev_rank, switched, missed
cdef int trials

def __cinit__(GIL_Battle self, int trials=100000):
    self.prev_tick = _Py_Ticker
    self.prev_rank = -1
    self.missed = 0
    self.switched = 0
    self.trials = trials

def record(GIL_Battle self, int rank):
    if self.trials == self.switched + self.missed:
        raise StopBattle   
    if self.prev_rank == -1:
        self.prev_tick = _Py_Ticker
        self.prev_rank = rank
    else:
        if _Py_Ticker > self.prev_tick:
            if self.prev_rank == rank:
                self.missed += 1
            else:
                self.switched += 1
            self.prev_tick = _Py_Ticker
            self.prev_rank = rank
        else:
            self.prev_tick = _Py_Ticker
           
def report(GIL_Battle self):
    return int(self.switched), int(self.missed)


More information about the Python-Dev mailing list