线程同步问题-condition Semaphore

问题:

引出问题:
下面代码的执行结果不为0

total = 0
def add():
    global total
    for i in range(10000000):
        total += 1
def desc():
    global total
    for i in range(10000000):
        total -= 1
import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)

解决方法:
1)线程同步工具-锁 lock

lock 枷锁后线程会交替进行加减操作。

from threading import Lock
total = 0
lock = Lock()
def add():
    global total
    global lock
    for i in range(10000000):
        lock.acquire()
        total += 1
        lock.release()

def desc():
    global total
    global lock
    for i in range(10000000):
        lock.acquire()
        total -= 1
        lock.release()

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)
-------------------------
0  #执行结果恒为0

加锁后的影响:
1)锁后会影响代码运行性能
2)锁有可能引起死锁(未释放,多次获取,互相等待)

2)线程同步工具-可重入的锁 RLock

特性

  1. 在同一个线程里面可以联系acquire多次(acquire 与 release次数相同)
from threading import Lock ,RLock
total = 0
lock = RLock()
def add():
    global total
    global RLock
    for i in range(10000000):
        lock.acquire()
        lock.acquire()
        lock.acquire()
        lock.acquire()
        lock.acquire()
        total += 1
        lock.release()
        lock.release()
        lock.release()
        lock.release()
        lock.release()

def desc():
    global total
    global lock
    for i in range(10000000):
        lock.acquire()
        lock.acquire()
        lock.acquire()
        lock.acquire()
        lock.acquire()
        total -= 1
        lock.release()
        lock.release()
        lock.release()
        lock.release()
        lock.release()

import threading
thread1 = threading.Thread(target=add)
thread2 = threading.Thread(target=desc)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)

-------------------------------------
0  #结果恒为0

条件变量:

类似两个人之间的交流功能,先用lock试下

import threading
class XIAOAITONGXUE(threading.Thread):
    def __init__(self,lock):
        super().__init__(name='小爱')
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:在".format(self.name))
        self.lock.release()

class TIANMAOJINGLING(threading.Thread):
    def __init__(self,lock):
        super().__init__(name='天猫精灵')
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:小爱同学 ".format(self.name))
        self.lock.release()

if __name__ == '__main__':
    lock = threading.Lock()
    tianmo = TIANMAOJINGLING(lock)
    xia = XIAOAITONGXUE(lock)
    tianmo.start()
    xia.start()
    -------------------------------------------------------
    天猫精灵:小爱同学 
	小爱:在

但是当我们想让他们实现对话的时候

import threading
class XIAOAITONGXUE(threading.Thread):
    def __init__(self,lock):
        super().__init__(name='小爱')
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:在".format(self.name))
        self.lock.release()

        self.lock.acquire()
        print("{}:好呀".format(self.name))
        self.lock.release()

class TIANMAOJINGLING(threading.Thread):
    def __init__(self,lock):
        super().__init__(name='天猫精灵')
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:小爱同学 ".format(self.name))
        self.lock.release()

        self.lock.acquire()
        print("{}:我们来对诗吧 ".format(self.name))
        self.lock.release()

if __name__ == '__main__':
    lock = threading.Lock()
    tianmo = TIANMAOJINGLING(lock)
    xia = XIAOAITONGXUE(lock)
    tianmo.start()
    xia.start()
    --------------------------------------------------------
    天猫精灵:小爱同学 
	天猫精灵:我们来对诗吧 
	小爱:在
	小爱:好呀

没有实现两个线程的交互

通过condition来完成:

在这里插入图片描述
condition中实现了enter exit协议,可以使用with语句
wait等待某个条件变量的通知
notify通知启动

condition有两层锁,一把底层锁会在线程调用wait方法时释放,上面的锁会在每次调用wait时重新分配一把并放到cond的等待队列中,等待notify方法的唤醒。

import threading
from threading import Condition
class XIAOAITONGXUE(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='小爱')
        self.cond = cond

    def run(self):
        with self.cond:
            #小哎等待接收消息
            self.cond.wait()
            print("{}:在".format(self.name)) #说话
            self.cond.notify() #通知说话

            # 小哎等待接收消息
            self.cond.wait()
            print("{}:好的呀".format(self.name))  # 说话
            self.cond.notify()  # 通知说话

            # 小哎等待接收消息
            self.cond.wait()
            print("{}:曲项向天歌".format(self.name))  # 说话
            self.cond.notify()  # 通知说话

            self.cond.wait()
            print("{}:红掌拨清波".format(self.name))  # 说话
            self.cond.notify()  # 通知说话


class TIANMAOJINGLING(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='天猫精灵')
        self.cond = cond

    def run(self):
        with self.cond:
                #天猫打招呼给小艾
                print("{}:小爱同学 ".format(self.name))
                self.cond.notify()  #通知
                self.cond.wait()    #等待

                # 天猫打招呼给小艾
                print("{}:我们来对诗吧 ".format(self.name))
                self.cond.notify()  # 通知
                self.cond.wait()  # 等待

                # 天猫打招呼给小艾
                print("{}:鹅鹅鹅 ".format(self.name))
                self.cond.notify()  # 通知
                self.cond.wait()  # 等待

                # 天猫打招呼给小艾
                print("{}:白毛浮绿水 ".format(self.name))
                self.cond.notify()  # 通知
                self.cond.wait()  # 等待

if __name__ == '__main__':
    cond = Condition()
    tianmo = TIANMAOJINGLING(cond)
    xia = XIAOAITONGXUE(cond)

    #注意启动顺序,如果先启动tianmo会notify通知xia,但是xia还没有启动
    #wait 与 notify 一定是调用condition之后才能使用。
    xia.start()
    tianmo.start()
    -----------------------------------------------------
	天猫精灵:小爱同学 
	小爱:在
	天猫精灵:我们来对诗吧 
	小爱:好的呀
	天猫精灵:鹅鹅鹅 
	小爱:曲项向天歌
	天猫精灵:白毛浮绿水 
	小爱:红掌拨清波

Semaphore限制并发数
import threading,time
from threading import Semaphore
class HtmlSpider(threading.Thread):
    def __init__(self,url,sem):
        super().__init__()
        self.url = url
        self.sem = sem

    def run(self):
        time.sleep(2)
        print(self.url,)
        #运行完成 释放
        self.sem.release()



class UrlProducer(threading.Thread):
    def __init__(self,sem):
        super().__init__()
        #传入一个Semaphore
        self.sem = sem

    def run(self):
        for i in range(30):
            #Semaphore内有 acquire  release
            self.sem.acquire()
            html_thread = HtmlSpider("https://baidu.com/{id}".format(id=i),self.sem)
            html_thread.start()



if __name__ == '__main__':
    sem = threading.Semaphore(3)
    url = UrlProducer(sem)
    url.start()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值