今天接着写多线程,最近几天一直在看多线程,但是书上的例子太难看了(可能我天生愚笨吧~_~),看了好久才搞懂,我看了两本书才搞明白书上的例子,所以大家在看书学习看不懂的时候,推荐多看几本一样知识点的书,在网上多看教程,辅助学习。
下面开始介绍锁和条件变量。
一。“锁”
锁是指在运行程序时,对于需要访问共享资源的多线程程序,为防止I/O密集型操作造成结果发生错误。
使用锁的方法: import threading
引入锁 lock = threading.Lock()
添加锁 lock.acquire()
对临界资源进行访问的代码
释放锁 lock.release()
假设对数字进行迭代输出,在不加锁的情况下,会导致输出全为15,加锁后是1,2,3,4.。。。。。13,14,15,最后输出‘all done'
对于添加锁,添加锁后就只能一个线程对公共资源进行访问,所以在执行时速度会变慢,因为执行时等同于同步运行。
示例一代码:
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
#导入模
import threading
import time
from atexit import register
import random
lock = threading.Lock()
a = 0
def print_sum():
global a
lock.acquire()
a += 1
time.sleep(1)
print(str(a))
lock.release()
def main():
th_list = []
for x in range(15):
t = threading.Thread(target=print_sum,args=())
th_list.append(t)
for x in th_list:
x.start()
@register
def exit():
print('all done')
if __name__ == '__main__':
main()
二。条件变量
对于条件变量,可以添加一个判断条件,如果符合条件就执行,否则等待。
导入模块 from threading import Condition
该模块有acquirre()和release(),在不符合条件时,调用.wait(),此时线程就会挂起,调用.notify() 或.notify_all()来激活线程,再进行条件判断。
以消费--生产问题来进行对条件变量讨论。创建一个产品类,一个消费者类,一个生产者类,消费者有五个线程,生产者有一个线程,生产者不断生产,消费者持续消费,不会存在无限生产消费不完的问题,但是停止程序需要手动完成。
代码:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import threading
import time
import random
#条件变量,消费者和生产者
#产品类
class Chan_pin():
def __init__(self):
self.count = 0
#消费产品
def xiao_fei(self):
self.count -= 1
#生产产品
def sheng_chan(self):
self.count += 1
#判断产品是否为空
def pan_duan(self):
return not self.count
pass
#生产类
class Sheng_chans(threading.Thread):
def __init__(self,tiao_jian,chan_pin):
super().__init__()
self.tiao_jian = tiao_jian
self.chan_pin = chan_pin
def run(self):
while True:
self.tiao_jian.acquire()
self.chan_pin.sheng_chan()
print('已生产的产品数:%s' % self.chan_pin.count)
self.tiao_jian.notify_all()
self.tiao_jian.release()
time.sleep(random.random())
pass
#创建消费类
class Xiao_fei(threading.Thread):
def __init__(self,chan_pin,tiao_jian):
super().__init__()
self.tiao_jian = tiao_jian
self.chan_pin = chan_pin
#重构run函数
def run(self):
while True:
self.tiao_jian.acquire()
time.sleep(random.randint(2,5))
if self.chan_pin.pan_duan():
self.tiao_jian.wait()
print('%s产品没了,请等待。。。' % threading.current_thread().name)
else:
self.chan_pin.xiao_fei()
print('%s已消费,现剩余产品:%s' % (threading.current_thread().name,self.chan_pin.count))
self.tiao_jian.notify_all()
self.tiao_jian.release()
pass
#创建实例。
def main():
tiao_jian = threading.Condition()
chan_pin = Chan_pin()
t1 = Sheng_chans(tiao_jian,chan_pin)
t1.start()
time.sleep(5)
#t1.join()
for x in range(5):
t2 = Xiao_fei(chan_pin,tiao_jian)
t2.start()
print(threading.active_count())
print(threading.enumerate())
print(threading.enumerate()[-2].is_alive())
#t2.join()
#运行
if __name__ == '__main__':
main()
三。信号量
信号量允许添加指定个数的线程对公共资源进行访问。
对于信号量有两个模块可用,分别是:Semaphore和BoundedSemaphore 前一个模块比第二个有一个缺点,第一个在进行调用.release()时,添加数超过设定数时不会报错,而第二个会进行报错。
本文章主要对第二个进行介绍。
该模块有两个方法, .acquire()和.release() 在调用.acquire()时会减一,当减到0时,会停止线程运行,进入等待;调用.release()时会加一。
调用方法:
num = 5 #表示只允许5个线程对公共资源进行访问。
a = BoundedSemaphore(num)
a.acquire()
要执行的代码
a.release()
下面是示例代码:
1 #!/usr/bin/env python3.6 2 # -*- coding: utf-8 -*- 3 #导入模 4 import threading 5 import time 6 from atexit import register 7 8 9 #要操作的公共资源,设置一个列表,多个线程对列表进行访问,输出列表内容。 10 11 num = 3 12 a = threading.BoundedSemaphore(num) 13 #创建一个输出内容的函数 14 def print_list(list): 15 a.acquire() 16 p = threading.current_thread().name 17 if a.acquire(False): 18 print('%s : 不能运行' % p) 19 else: 20 print('%s:%s' % (p,list)) 21 a.release() 22 23 #继承线程类 24 class New_thread(threading.Thread): 25 def __init__(self,han_name,han_can): 26 super().__init__() 27 self.han_name = han_name #函数名 28 self.han_can = han_can #要传入函数的参数 29 def run(self): 30 self.han_name(self.han_can) 31 pass 32 33 # 34 def main(): 35 list_1 = ['aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff'] 36 #线程列表 37 thread_list = [] 38 #创建十个线程 39 for x in range(5): 40 t = New_thread(print_list,list_1) 41 thread_list.append(t) 42 for x in thread_list: 43 x.start() 44 #print(thread_list) 45 46 #创建回调函数。 47 @register 48 def exit(): 49 print('all done') 50 51 if __name__ == '__main__': 52 main()
以上就是关于多线程的锁,信号量,条件变量,有不对的地方还望多指教。