运维开发网

python 线程条件变量Condition(31)

运维开发网 https://www.qedev.com 2020-01-24 21:49 出处:网络 作者:qq5d6f345f0205e
对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition.  一.线程条件变量Condition相关函数介绍acquire() —  线程锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作;release()

对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition.

 

python 线程条件变量Condition(31)

 

一.线程条件变量Condition相关函数介绍

acquire() —  线程锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作;

release() — 释放锁,注意线程条件变量Condition中的所有相关函数使用必须在acquire() /release() 内部操作;

wait(timeout) —  线程挂起(阻塞状态),直到收到一个notify通知或者超时才会被唤醒继续运行(超时参数默认不设置,可选填,类型是浮点数,单位是秒)。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError;

notify(n=1) —  通知其他线程,那些挂起的线程接到这个通知之后会开始运行,缺省参数,默认是通知一个正等待通知的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError,notify()不会主动释放Lock;

notifyAll() —  如果wait状态线程比较多,notifyAll的作用就是通知所有线程;

 

python 线程条件变量Condition(31)

 

 

二.线程条件变量Condition原理

在前面的文章已经介绍过互斥锁,主要作用是并行访问共享资源时,保护共享资源,防止出现脏数据。python 条件变量Condition也需要关联互斥锁,同时Condition自身提供了wait/notify/notifyAll方法,用于阻塞/通知其他并行线程,可以访问共享资源了。可以这么理解,Condition提供了一种多线程通信机制,假如线程1需要数据,那么线程1就阻塞等待,这时线程2就去制造数据,线程2制造好数据后,通知线程1可以去取数据了,然后线程1去获取数据。

python 线程条件变量Condition(31)

三.线程条件变量Condition使用

案例一:成语接龙

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

# !usr/bin/env python

# -*- coding:utf-8 _*-

"""

@Author:何以解忧

@Blog(个人博客地址): shuopython.com

@WeChat Official Account(微信公众号):猿说python

@Github:www.github.com

@File:python_.py

@Time:2019/10/21 21:25

 

@Motto:不积跬步无以至千里,不积小流无以成江海,程序人生的精彩需要坚持不懈地积累!

"""

 

# 导入线程模块

import threading

 

# 创建条件变量condition

con = threading.Condition()

 

def thread_one(name):

    # 条件变量condition 线程上锁

    con.acquire()

 

    print("{}:成语接龙准备好了吗".format(name))

    # 唤醒正在等待(wait)的线程

    con.notify()

 

    # 等待对方回应消息,使用wait阻塞线程,等待对方通过notify唤醒本线程

    con.wait()

    print("{}:一干二净".format(name))

    # 唤醒对方

    con.notify()

 

    # 等待消息答应

    con.wait()

    print("{}:一天就知道看抖音美女,给你来个简单点的,来了:毛手毛脚".format(name))

    # 唤醒对方

    con.notify()

 

    # 等待消息答应

    con.wait()

    print("{}:哟哟哟,不错不错!".format(name))

    # 唤醒对方

    con.notify()

 

    # 条件变量condition 线程释放锁

    con.release()

 

def thread_two(name):

    # 条件变量condition 线程上锁

    con.acquire()

 

    # wait阻塞状态,等待其他线程通过notify唤醒本线程

    con.wait()

    print("{}:准备好了~开始吧!".format(name))

    # 唤醒对方

    con.notify()

 

    # 等待消息答应

    con.wait()

    print("{}:净你妹啊,没法接...来个简单点的...".format(name))

    # 唤醒对方

    con.notify()

 

    # 等待消息答应

    con.wait()

    print("{}:嘿,这个我知道:脚踏实地".format(name))

    # 唤醒对方

    con.notify()

 

    con.release()

 

if __name__ == "__main__":

 

    # 创建并初始化线程

    t1 = threading.Thread(target=thread_one,args=("A"))

    t2 = threading.Thread(target=thread_two,args=("B"))

 

    # 启动线程 -- 注意线程启动顺序,启动顺序很重要

    t2.start()

    t1.start()

 

    # 阻塞主线程,等待子线程结束

    t1.join()

    t2.join()

 

 

    print("程序结束!")

输出结果:

1

2

3

4

5

6

7

8

A:成语接龙准备好了吗

B:准备好了~开始吧!

A:一干二净

B:净你妹啊,没法接...来个简单点的...

A:一天就知道看抖音美女,给你来个简单点的,来了:毛手毛脚

B:嘿,这个我知道:脚踏实地

A:哟哟哟,不错不错!

程序结束!

python 线程条件变量Condition(31)

案例二:生产者与消费者模式,以吃火锅为例:一盘老肉片有10块肉,吃完了又重新往锅里加….

生产者:往锅里加老肉片,每次加一盘(10块);

消费者:吃煮熟的肉片,没吃一片,肉片数量减一,吃完为止;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

# 导入线程模块

import threading

import time

 

# 创建条件变量condition

con = threading.Condition()

meat_num = 0

 

def thread_consumers():

    # 条件变量condition 线程上锁

    con.acquire()

    

    # 全局变量声明关键字 global

    global meat_num

    meat_num = 0

 

    # 等待肉片下锅煮熟

    con.wait()

    while True:

        print("我来一块肉片...")

        meat_num -= 1

        print("剩余肉片数量:%d"%meat_num)

        time.sleep(0.5)

        if meat_num == 0:

            # 肉片吃光了,通知老板添加肉片

            print("老板,再来一份老肉片...")

            con.notify()

            # 肉片吃光了,等待肉片

            con.wait()

 

    # 条件变量condition 线程释放锁

    con.release()

 

 

def thread_producer():

    # 条件变量condition 线程上锁

    con.acquire()

    # 全局变量声明关键字 global

    global meat_num

 

    # 肉片熟了,可以开始吃了

    meat_num = 10

    print("肉片熟了,可以开始吃了...")

    con.notify()

    while True:

        # 阻塞函数,等待肉片吃完的通知

        con.wait()

        meat_num = 10

        # 添加肉片完成,可以继续开吃

        print("添加肉片成功!当前肉片数量:%d"%meat_num)

        time.sleep(1)

        con.notify()

 

    con.release()

 

 

if __name__ == "__main__":

    # 创建并初始化线程

    t1 = threading.Thread(target=thread_producer)

    t2 = threading.Thread(target=thread_consumers)

 

    # 启动线程 -- 注意线程启动顺序,启动顺序很重要

    t2.start()

    t1.start()

 

    # 阻塞主线程,等待子线程结束

    t1.join()

    t2.join()

 

    print("程序结束!")

输出结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

肉片熟了,可以开始吃了...

我来一块肉片...

剩余肉片数量:9

我来一块肉片...

剩余肉片数量:8

我来一块肉片...

剩余肉片数量:7

我来一块肉片...

剩余肉片数量:6

我来一块肉片...

剩余肉片数量:5

我来一块肉片...

剩余肉片数量:4

我来一块肉片...

剩余肉片数量:3

我来一块肉片...

剩余肉片数量:2

我来一块肉片...

剩余肉片数量:1

我来一块肉片...

剩余肉片数量:0

老板,再来一份老肉片...

添加肉片成功!当前肉片数量:10

我来一块肉片...

剩余肉片数量:9

我来一块肉片...

剩余肉片数量:8

我来一块肉片...

剩余肉片数量:7

.............

注意:

1.全局变量要声明关键字 global;

2.注意线程的启动顺序,这个很重要;

 

四.重点总结

注意线程互斥锁Lock/线程事件Event/线程条件变量Condition三者的区别,场景不同,使用方式也不同,前两者一般可以作为简单的线程交互,线程条件变量Condition可以用于比较复杂的线程交互!

猜你喜欢:

1.python线程创建和参数传递

2.python线程互斥锁Lock

3.python线程事件Event

4.python return逻辑判断表达式

 

转载请注明:猿说Python » python条件变量Condition

0

精彩评论

暂无评论...
验证码 换一张
取 消