I want to release the GIL

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Piotr Sobolewski

    I want to release the GIL

    Hello,
    I have such program:

    import time
    import thread
    def f():
        global lock
        while True:
            lock.acquire()
            print thread.get_iden t()
            time.sleep(1)
            lock.release()
    lock=thread.all ocate_lock()
    thread.start_ne w_thread(f,())
    thread.start_ne w_thread(f,())
    time.sleep(60)

    As you can see, I start two threads. Each one works in an infinite
    loop.
    Inside that loop it acquires lock, prints its own id, sleeps a bit and
    then
    releases lock.

    When I run it, I notice that only one thread works and the other one
    never
    has a chance to run. I guess it is because the thread don't have a
    chance
    to release the GIL - after it releases the lock, it almost immediately
    (in
    the very next bytecode command) reacquires it. I know I can
    put "time.sleep(0.0 1)" command after between release and reacquire,
    but it
    doesn't seem elegant - why should I make my program sleep instead of
    work?

    Is there any simple way to release the GIL? Like:
    lock.release()
    thread.release_ gil()
    ?

    Thanks in advance!
  • Chris Rebert

    #2
    Re: I want to release the GIL

    On Mon, Oct 20, 2008 at 10:12 PM, Piotr Sobolewski
    <piotr_sobolews ki@o2.plwrote:
    Hello,
    I have such program:
    >
    import time
    import thread
    def f():
    global lock
    while True:
    lock.acquire()
    print thread.get_iden t()
    time.sleep(1)
    lock.release()
    lock=thread.all ocate_lock()
    thread.start_ne w_thread(f,())
    thread.start_ne w_thread(f,())
    time.sleep(60)
    >
    As you can see, I start two threads. Each one works in an infinite
    loop.
    Inside that loop it acquires lock, prints its own id, sleeps a bit and
    then
    releases lock.
    >
    When I run it, I notice that only one thread works and the other one
    never
    has a chance to run. I guess it is because the thread don't have a
    chance
    to release the GIL - after it releases the lock, it almost immediately
    (in
    the very next bytecode command) reacquires it. I know I can
    put "time.sleep(0.0 1)" command after between release and reacquire,
    but it
    doesn't seem elegant - why should I make my program sleep instead of
    work?
    You let *one thread* sleep so that the *other thread* can wake, grab
    the lock, and *work*.

    Cheers,
    Chris
    --
    Follow the path of the Iguana...

    >
    Is there any simple way to release the GIL? Like:
    lock.release()
    thread.release_ gil()
    ?
    >
    Thanks in advance!
    --

    >

    Comment

    • Carl Banks

      #3
      Re: I want to release the GIL

      On Oct 21, 1:12 am, Piotr Sobolewski <piotr_sobolew. ..@o2.plwrote:
      Hello,
      I have such program:
      >
      import time
      import thread
      def f():
          global lock
          while True:
              lock.acquire()
              print thread.get_iden t()
              time.sleep(1)
              lock.release()
      lock=thread.all ocate_lock()
      thread.start_ne w_thread(f,())
      thread.start_ne w_thread(f,())
      time.sleep(60)
      Let me state first of all that you are going about it all wrong.
      Simple locks don't handle the above siutation very well because,
      frankly, there's no benefit to using threads in this way at all.
      Since neither thread can run at the same time as the other, you might
      as well have just used ordinary looping.

      Normally, when using threads, you only want to use locking for brief
      periods when accessing data shared between threads, like so:

      def f():
      do_some_stuff
      lock.acquire()
      access_shared_d ata
      lock.release()
      do_some_more_st uff

      Starvation is much less likely to occur in this situation. (The
      interpreter periodically releases the GIL, so if there's stuff between
      a release and the next acquire, it'll have a window in which to
      release the GIL--unlike in your example where the window was very
      tiny.)


      As you can see, I start two threads. Each one works in an infinite
      loop.
      Inside that loop it acquires lock, prints its own id, sleeps a bit and
      then
      releases lock.
      >
      When I run it, I notice that only one thread works and the other one
      never
      has a chance to run. I guess it is because the thread don't have a
      chance
      to release the GIL - after it releases the lock, it almost immediately
      (in
      the very next bytecode command) reacquires it.
      Not really the GIL's fault. Or rather, fiddling with the GIL is the
      wrong way to get what you want here.

      What you want is some kind of thread balancing, to make sure all
      threads have a chance to run. Let me stress that, in this case, you
      only need balancing because you're using threads incorrectly. But
      I'll mention one way to do it anyway.

      The easiest way I can think of is to use a counter that is protected
      by a threading.Condi tion. One thread only runs when the counter is
      even, the other only when it's odd. It might be implemented like
      this:


      counter = 0
      c = threading.Condi tion()

      def f():
      global counter
      c.acquire()
      while counter % 1 == 0: # == 1 for the other thread
      c.wait()
      do_something()
      counter += 1
      c.notify()
      c.release()


      The reason threading.Condi tion is required and not a simple lock is
      that simply acquiring the lock is not enough; the counter must be in
      the right state as well.


      Carl Banks

      Comment

      Working...