Semaphore semaphore semaphore of threading

Posted by hedge on Sun, 01 Dec 2019 11:07:41 +0100

Simple code demonstration of semaphore semaphore semaphore

import threading
import logging
import time

FORMAT = '%(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)

def worker(s:threading.Semaphore):
    logging.info('in sub thread')
    logging.info(s.acquire())   # Get semaphore, counter-1
    logging.info('sub thread over')

s = threading.Semaphore(3)   # Create 3 semaphore counters
logging.info(s.acquire())
print(s._value)    # Let's see what's in the semaphore now
logging.info(s.acquire())
print(s._value)
logging.info(s.acquire())
print(s._value)

threading.Thread(target=worker, args=(s, )).start()

time.sleep(2)

logging.info(s.acquire(False))    # No blocking, False if no semaphore is available
logging.info(s.acquire(timeout=10))   # Set the time-out time. After the time-out time, no signal has been obtained. The return value is False

# release
logging.info('released')
s.release()   # Release semaphore, counter i + 1

Simple resource pool demonstration

import threading
import logging
import random

FORMAT = '%(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)

class Conn:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

class Pool:
    def __init__(self, count:int):
        self.count = count
        self.pool = [ self._connect('conn-{}'.format(x)) for x in range(self.count)]

    def _connect(self, conn_name):
        return Conn(conn_name)

    def get_conn(self):
        conn = self.pool.pop()
        return conn

    def return_conn(self, conn:Conn):
        self.pool.append(conn)

pool = Pool(3)

def worker(pool:Pool):
    conn = pool.get_conn()
    logging.info(conn)
    threading.Event().wait(random.randint(1,4))
    pool.return_conn(conn)

for i in range(6):
    threading.Thread(target=worker, name='worker-{}'.format(i), args=(pool,)).start()       

Using semaphore to refine the code

import threading
import logging
import random

FORMAT = '%(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)

class Conn:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

class Pool:
    def __init__(self, count:int):
        self.count = count
        self.pool = [ self._connect('conn-{}'.format(x)) for x in range(self.count)]
        self.semahore = threading.Semaphore(count)

    def _connect(self, conn_name):
        return Conn(conn_name)

    def get_conn(self):
        self.semahore.acquire()
        conn = self.pool.pop()
        return conn

    def return_conn(self, conn:Conn):
        self.pool.append(conn)
        self.semahore.release()

pool = Pool(3)

def worker(pool:Pool):
    conn = pool.get_conn()
    logging.info(conn)
    threading.Event().wait(random.randint(1,4))
    pool.return_conn(conn)

for i in range(6):
    threading.Thread(target=worker, name='worker-{}'.format(i), args=(pool,)).start()

On the problem that the semaphore release exceeds the range of initial value

When we use semaphore, if we haven't yet acquire d it, we will release it. What's the problem?
The value of the generated semaphore is + 1, which exceeds the initial value of semaphore. The following example shows this problem

import threading
import logging

FORMAT = '%(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)

sema = threading.Semaphore(3)
logging.warning(sema.__dict__)
for _ in range(3):
    sema.acquire()

logging.warning('-----')
logging.warning(sema.__dict__)

for _ in range(4):
    sema.release()
logging.warning(sema.__dict__)

for _ in range(3):
    sema.acquire()
logging.warning('--------')
logging.warning(sema.__dict__)
sema.acquire()
logging.warning('======')
logging.warning(sema.__dict__)

Therefore, the BoundedSemaphore class can be used to implement the bounded semaphore. If the release exceeds the range of the initial value, a ValueError exception will be thrown

Topics: Python