共享变量
- 概念: 当多个线程同时访问一个变量的时候,会产生共享变量的问题
# 不启用多线程,正常执行结果
import threading
sum = 0
loopSum = 100000
def myAdd():
global sum, loopSum
for i in range(1, loopSum):
sum += 1
def myMinu():
global sum, loopSum
for i in range(1, loopSum):
sum -= 1
if __name__ == '__main__':
myAdd()
print(sum)
myMinu()
print(sum)
99999
0
# 多线程执行两个方法
import threading
sum = 0
loopSum = 100000
def myAdd():
global sum, loopSum
for i in range(1, loopSum):
sum += 1
def myMinu():
global sum, loopSum
for i in range(1, loopSum):
sum -= 1
if __name__ == '__main__':
print("Stating ....{0}".format(sum))
# 启用多线程实例,查看执行结果
t1 = threading.Thread(target=myAdd, args=())
t2 = threading.Thread(target=myMinu, args=())
t1.start()
t2.start()
t1.join()
t2.join()
print("Done .... {0}".format(sum))
Stating ....0
Done .... -31331
解决方案: 锁,
- 锁(LOCK):
- 是一个标志,表示一个线程在占用一些资源
- 使用方法:
- 上锁
- 使用共享资源
- 释放锁
- 琐谁:
- 那个资源需要多线程共享,锁那个
- 理解锁:
- 锁其实是一个令牌,并且这个令牌只有一个,访问共享资源时需要去申请这个令牌,只有申请到令牌的线程才能操作共享资源,操作完成后,需将令牌归还
import threading
sum = 0
loopSum = 100000
# 定义锁
lock = threading.Lock()
def myAdd():
global sum, loopSum
for i in range(1, loopSum):
# 加锁,申请锁
lock.acquire()
sum += 1
# 释放锁
lock.release()
def myMinu():
global sum, loopSum
for i in range(1, loopSum):
# 加锁,申请锁
lock.acquire()
sum -= 1
# 释放锁
lock.release()
if __name__ == '__main__':
print("Stating ....{0}".format(sum))
# 启用多线程实例,查看执行结果
t1 = threading.Thread(target=myAdd, args=())
t2 = threading.Thread(target=myMinu, args=())
t1.start()
t2.start()
t1.join()
t2.join()
print("Done .... {0}".format(sum))
Stating ....0
Done .... 0
线程安全问题:
- 如果一个资源/变量,它对于多线程来讲,不用加锁也不会引起任何问题,则称为线程安全。
- 线程不安全变量类型:list,set,dict
- 线程安全变量类型:queue
- 生产者消费者问题
- 一个模型,用来搭建消息队列
- queue 是一个用来存放变量的数据结构,特点是先进先出,内部元素排队,可以理解成一个特殊的list
import threading
import time
import queue
# python2
# from Queue import Queue
# python3
class Produer(threading.Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() < 1000:
for i in range(100):
count = count + 1
msg = "生成产品" + str(count)
queue.put(msg)
print(msg)
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global queue
while True:
if queue.qsize() > 100:
for i in range(3):
msg = self.name + "消费了" + queue.get()
print(msg)
time.sleep(1)
if __name__ == "__main__":
queue = queue.Queue()
for i in range(500):
queue.put("初始产品:"+str(i))
for i in range(2):
p = Produer()
p.start()
for i in range(5):
c = Consumer()
c.start()
死锁
import threading
import time
lock_1 = threading.Lock()
lock_2 = threading.Lock()
def funca():
print("A 函数启动....")
print("A 申请了锁1...")
lock_1.acquire()
print("A 等待申请锁2...")
time.sleep(2)
lock_2.acquire()
print("A 释放了锁2...")
lock_2.release()
print("A 释放了锁1")
lock_1.release()
print("A 函数执行结束...")
def funcb():
print("B 函数启动...")
print("B 函数申请锁2...")
lock_2.acquire()
print("B 函数等待申请锁1...")
time.sleep(4)
print("B 函数申请申请锁1...")
lock_1.acquire()
print("B 函数释放锁1...")
lock_1.release()
print("B 函数释放锁2...")
lock_2.release()
print("B 函数执行结束...")
if __name__ == '__main__':
t1 = threading.Thread(target=funca, args=())
t2 = threading.Thread(target=funcb, args=())
t1.start()
t2.start()
t1.join()
t2.join()
- 锁的等待时间
import threading
import time
lock_1 = threading.Lock()
lock_2 = threading.Lock()
def funca():
print("A 函数启动....")
print("A 申请了锁1...")
lock_1.acquire(timeout=4)
print("A 等待申请锁2...")
time.sleep(2)
res = lock_2.acquire(timeout=2)
if res:
print("A 得到了锁2...")
lock_2.release()
print("A 释放了锁2...")
else:
print("A 没有申请到锁2...")
print("A 释放了锁1")
lock_1.release()
print("A 函数执行结束...")
def funcb():
print("B 函数启动...")
print("B 函数申请锁2...")
lock_2.acquire()
print("B 函数等待申请锁1...")
time.sleep(4)
print("B 函数申请申请锁1...")
lock_1.acquire()
print("B 函数释放锁1...")
lock_1.release()
print("B 函数释放锁2...")
lock_2.release()
print("B 函数执行结束...")
if __name__ == '__main__':
t1 = threading.Thread(target=funca, args=())
t2 = threading.Thread(target=funcb, args=())
t1.start()
t2.start()
t1.join()
t2.join()
- semphore
- 允许一个资源最多由几个线程同时使用
import threading
import time
# 参数定义同一个资源最多几个线程同时使用
semphore = threading.Semaphore(3)
def func():
if semphore.acquire():
for i in range(5):
print(threading.currentThread().getName() + "get semphore")
time.sleep(15)
semphore.release()
print(threading.currentThread().getName() + "release semphore")
for i in range(8):
t1 = threading.Thread(target=func)
t1.start()
- threading.Timer
-Timer : 是利用多线程在指定时间后启动一个功能
import threading
import time
def func():
print("I am body")
time.sleep(4)
print("bay")
if __name__ == "__main__":
t1 = threading.Timer(6, func)
t1.start()
i = 0
while i < 6:
print("{0}..........".format(i))
time.sleep(2)
i += 1
0..........
1..........
2..........
I am body
3..........
4..........
bay
5..........
- 可重入锁:
- 可以被一个线程多次申请
- 主要解决递归调用的时候,需要申请锁的情况(递归调用多次申请锁)
import threading
import time
lock = threading.RLock()
class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1)
if lock.acquire(1):
num += 1
msg = self.name + 'set num to ' + str(num)
print(msg)
lock.acquire()
lock.release()
lock.release()
num = 0
def mytherad():
for i in range(8):
t1 = MyThread()
t1.start()
if __name__ == '__main__':
mytherad()
Thread-77set num to 1
Thread-78set num to 2
Thread-79set num to 3
Thread-80set num to 4
Thread-81set num to 5
Thread-82set num to 6
Thread-83set num to 7
Thread-84set num to 8