1、线程锁
#! /usr/bin/evn python3
# --*-- coding: utf-8 --*--
from threading import Lock,RLock
import threading
#说明:
# 1、用锁会影响性能(必然存在的)
# 2、锁会引起死锁
# 死锁两种常见的情况:
# 1、lock.acquire() lock.acquire()两次使用锁而无释放
# 2、资源竞争
'''A(a,b)
acquire(a)
acquire(b)
B(a,b)
acquire(a)
acquire(b)
'''
# 3、两次调用lock.acquire()
# 解决办法:Python中引入了可重入的锁from threading import RLock
# 说明:在同一个线程里面,可以连续调用多次acquire(),一定要注意acquire()调用要和release()调用次数一致
'''
def add():
global total
global lock
for i in range(1000000):
lock.acquire()
dosomething(lock)
total += 1
lock.release()
def dosomething():
lock.acquire()
lock.release()
'''
#锁解决数据不一致问题
total = 0
lock = Lock()
def add():
global total
global lock
for i in range(1000000):
lock.acquire()
total += 1
lock.release()
def desc():
global total
global lock
for j in range(1000000):
lock.acquire()
total -= 1
lock.release()
threading1 = threading.Thread(target = add)
threading2 = threading.Thread(target= desc)
threading1.start()
threading2.start()
threading1.join()
threading2.join()
print(total)
#解决可以多次使用acquire()问题
total = 0
lock = RLock()
def add():
global total
global lock
for i in range(1000000):
lock.acquire()
lock.acquire()
total += 1
lock.release()
lock.release()
def desc():
global total
global lock
for j in range(1000000):
lock.acquire()
total -= 1
lock.release()
threading1 = threading.Thread(target = add)
threading2 = threading.Thread(target= desc)
threading1.start()
threading2.start()
threading1.join()
threading2.join()
print(total)
2、线程条件变量
#! /usr/bin/evn python3
# --*-- coding: utf-8 --*--
#线程中的条件变量()
# 通知天猫与小爱之间的来回切换
import threading
class XiaoAi(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 TianMao(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()
xiaoai = XiaoAi(lock)
tianmao = TianMao(lock)
tianmao.start()
xiaoai.start()
#wait() 等待某个条件变量的通知
#notify() 通知调用了wait()方法的启动
from threading import Condition
class XiaoAi(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()
self.cond.wait()
print("{} : 此恨何时已!".format(self.name))
self.cond.notify()
self.cond.wait()
print("{} : 定不负相思意!".format(self.name))
self.cond.notify()
self.cond.wait()
class TianMao(threading.Thread):
def __init__(self,cond):
super().__init__(name="天猫精灵")
self.cond = cond
def run(self):
with self.cond:#也可以这样调用:self.cond.acquire()方法,但一定要self.cond.release()方法
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()
print("{} : 此水几时休!".format(self.name))
self.cond.notify()
self.cond.wait()
print("{} : 只愿君心似我心!".format(self.name))
self.cond.notify()
self.cond.wait()
if __name__ == "__main__":
cond = threading.Condition()
xiaoai = XiaoAi(cond)
tianmao = TianMao(cond)
#启动顺序很重要
#我们先要一定调用Condition with()方法,with就相当于调用
#在调用with之后 cond之后才能调用wait()或者notify()方法
#condition有两层锁,一把底层锁会在线程调用了wait方法的时候释放,上面的锁会在每次调用wait()的时候分配一把并放入condition等待队列中,等待notify()方法的唤醒。
xiaoai.start()
tianmao.start()
3、线程信号量
#! /usr/bin/evn python3
# --*-- coding: utf-8 --*--
#Semaphore是用于控制进入数量的锁
#文件, 读、写, 写一般只是用于一个线程写,读可以允许有多个
#简单的模拟一个爬虫
import threading
import time
class HtmlSpider(threading.Thread):
def __init__(self,url,sem):
super().__init__()
self.url = url
self.sem = sem
def run(self):
time.sleep(2)
print("got html text success")
self.sem.release()
class UrlProducer(threading.Thread):
def __init__(self,sem):
super().__init__()
self.sem = sem
def run(self):
for i in range(20):
self.sem.acquire()
html_thread = HtmlSpider("https://baidu.com/{}".format(i),self.sem)
html_thread.start()
if __name__ == "__main__":
sem = threading.Semaphore(3)
url_producer = UrlProducer(sem)
url_producer.start()