码迷,mamicode.com
首页 > 编程语言 > 详细

Python多线程同步Lock\RLock\Semaphore

时间:2020-04-27 22:14:38      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:线程并发   star   lib   int   rom   多个   ==   error:   忘记   

不同步的情况

# encoding: UTF-8
import threading
import time

num = 0


class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
        num = num + 1
        msg = self.name + ‘ set num to ‘ + str(num)
        print msg + "\n"


def test():
    for i in range(5):
        t = MyThread()
        t.start()


if __name__ == ‘__main__‘:
    test()

## 输出
Thread-2 set num to 1
Thread-1 set num to 2
Thread-5 set num to 4
Thread-3 set num to 5
Thread-4 set num to 5

互斥量(mutex)

Lock

import threading

# 创建锁
mutex = threading.Lock()
# 申请锁
mutex.acquire(True)
# 释放锁
mutex.release()

通过Lock实现多线程同步

# encoding: UTF-8
import threading
import time


num = 0
mutex = threading.Lock() # 创建锁


class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)
        if mutex.acquire(True): # 申请锁,如果没抢占到锁,会一直阻塞(block)
            num = num + 1
            msg = self.name + ‘ set num to ‘ + str(num)
            print msg + "\n"
            mutex.release() # 释放锁


def test():
    for i in range(5):
        t = MyThread()
        t.start()


if __name__ == ‘__main__‘:
    test()
    
## 输出
Thread-1 set num to 1
Thread-2 set num to 2
Thread-4 set num to 3
Thread-3 set num to 4
Thread-5 set num to 5

使用mutex.acquiremutex.release显得比较繁琐,也不安全(比如编程人员忘记释放锁),可以使用with来替代。

# encoding: UTF-8
import threading
import time


class MyThread(threading.Thread):

    def __init__(self, mutex):
        super(MyThread, self).__init__()
        self.mutex = mutex

    def run(self):
        global num
        time.sleep(1)
        with self.mutex: # with语句,安全申请和释放锁。
            num = num + 1
            msg = self.name + ‘ set num to ‘ + str(num)
            print msg + "\n"


num = 0
mutex = threading.Lock()


def test():
    for i in range(5):
        t = MyThread(mutex)
        t.start()


if __name__ == ‘__main__‘:
    test()

Lock是不允许递归的,一个线程多次申请,将出现死锁。

import threading  
lock = threading.Lock() #Lock对象  
lock.acquire()  
lock.acquire()  #产生了死琐。  
lock.release()  
lock.release()  

RLock(递归锁)

Lock\RLock这两种琐的主要区别是:

RLock允许在同一线程中被多次acquire。

而Lock却不允许这种情况。

注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。

import threading  
rLock = threading.RLock()  #RLock对象  
rLock.acquire()  
rLock.acquire() #在同一线程内,程序不会堵塞。  
rLock.release()  
rLock.release()  

信号量(Semaphore)

信号量管理一个内部计数器,该计数器在每次acquire()调用时递减,在每次release()调用时递增。计数器永远不会低于零;当acquire()发现它为0时,它就阻塞,直到其他线程调用release()。

信号量Semaphore和互斥量mutex的最大差别是,信号量允许多个线程同时访问一个对象,而互斥量限制只能一个线程访问对象。

假如有一个连接池connection_pool维护着三个连接,如果有5个线程并发访问,则容易出现连接池没有可用连接的异常情况。例如:

# encoding: UTF-8
import threading
import time


connection_pool = [‘connection1‘, ‘connection2‘, ‘connection3‘] # 连接池


class MyThread(threading.Thread):

    def __init__(self):
        super(MyThread, self).__init__()

    def run(self):
        global connection_pool
        time.sleep(1)
        connection = connection_pool.pop() # 取出连接
        print "get connection %s" % connection + "\n"
        connection_pool.append(connection) # 放回连接


def test():
    for i in range(5):
        t = MyThread()
        t.start()


if __name__ == ‘__main__‘:
    test()

# 输出:
Exception in thread Thread-4:
Traceback (most recent call last):
  File "C:\Python27\lib\threading.py", line 801, in __bootstrap_inner
    self.run()
  File "./with_Semaphore.py", line 17, in run
    connection = connection_pool.pop()
IndexError: pop from empty list

这时,就可以使用Semaphore控制同时访问connection_pool的线程数。

# encoding: UTF-8
import threading
import time


connection_pool = [‘connection1‘, ‘connection2‘, ‘connection3‘]
semaphore = threading.Semaphore(3)


class MyThread(threading.Thread):

    def __init__(self, semaphore):
        super(MyThread, self).__init__()
        self.semaphore = semaphore

    def run(self):
        global connection_pool
        time.sleep(1)
        with self.semaphore:
            connection = connection_pool.pop()
            print "get connection %s" % connection + "\n"
            connection_pool.append(connection)


def test():
    for i in range(5):
        t = MyThread(semaphore)
        t.start()


if __name__ == ‘__main__‘:
    test()
# 输出:
get connection connection3
get connection connection2
get connection connection2
get connection connection2
get connection connection3

Python多线程同步Lock\RLock\Semaphore

标签:线程并发   star   lib   int   rom   多个   ==   error:   忘记   

原文地址:https://www.cnblogs.com/cnwenf/p/12790435.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!