Python多线程学习(中)

  今天接着写多线程,最近几天一直在看多线程,但是书上的例子太难看了(可能我天生愚笨吧~_~),看了好久才搞懂,我看了两本书才搞明白书上的例子,所以大家在看书学习看不懂的时候,推荐多看几本一样知识点的书,在网上多看教程,辅助学习。

下面开始介绍锁和条件变量。

一。“锁”

锁是指在运行程序时,对于需要访问共享资源的多线程程序,为防止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()

 

以上就是关于多线程的锁,信号量,条件变量,有不对的地方还望多指教。 

转载于:https://www.cnblogs.com/sniper-huohuohuo/p/8854833.html

你可能感兴趣的:(Python多线程学习(中))