我的Python成长之路---第八天---Python基础(24)---2016年3月5日(晴)

多线程编程

什么是多线程,线程是操作系统能够进行运算调度的最小单位。他包含在进程之中,是进程中的实际运作单位。线程是进程中一个单顺序的空值六,一个进程可以并发多个线程,每个线程可以并行处理不同的任务。

threading模块

python的标准库提供了两个模块用于多线程处理,_thread和threading,_thread是低级模块,threading是高级模块,是对_thread进行了封装。

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

线程有两种调用方式:直接调用和继承式调用

直接调用


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

#!/usr/bin/env python

# coding:utf-8

‘‘‘

Created on: 2016年5月16日

@author: 张晓宇

Email: [email protected]

Version: 1.0

Description: 多线程演示程序,直接启动方式

Help:

‘‘‘

def sayhi(num): # 定义每隔线程都要运行的函数

    print(‘%s is say hi‘ %num)

    import time

    time.sleep(3)

import threading

if __name__ == ‘__main__‘:

    t1 = threading.Thread(target = sayhi, args = [1, ]) # 调用Thread方法生成一个线程实例,第一个参数tartget表示进程要执行的函数,args表示要传递给进程函数的参数

    t2 = threading.Thread(target = sayhi, args = [2, ])

    t1.start() # 启动进程

    t2.start()

    t1.join() # 等待子进程完毕,这句话的意思就等待一个进程执行完在执行这句话后面的逻辑,join方法还可以接收一个超时时间参数,表示最多等待多长时间,超过这个时间就不等了,继续执行下面的语句,注意,是不等待,不是中断进程的执行

    t2.join()

    print(t1.getName()) # getName()表示获取进程的名称,默认Thread-1、Thread-2...这种命名方式

    print(t2.getName())

继承式调用


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

#!/usr/bin/env python

# coding:utf-8

‘‘‘

Created on:

@author: 张晓宇

Email: [email protected]

Version: 1.0

Description: 多线程演示程序,继承式调用

Help:

‘‘‘

import threading

class Mythreading(threading.Thread):

    ‘‘‘

    定义一个类,继承自threading.Thread

    ‘‘‘

    def __init__(self, num):

        ‘‘‘

        初始化方法

        :param num:

        :return:

        ‘‘‘

        threading.Thread.__init__(self)

        self.num = num

    def run(self):

        ‘‘‘

        重写run方法,也就是每个线程要执行的函数

        :return:

        ‘‘‘

        print(‘%s is say hi‘ %self.num)

        import time

        time.sleep(5)

if __name__ == ‘__main__‘:

    t1 = Mythreading(1) # 用刚才定义的类创建进程对象

    t2 = Mythreading(2)

    t1.start()

    t2.start()

    t1.join()

    t2.join()

    print(t1.getName())

    print(t2.getName())

守护线程

默认情况下,线程执行完毕如果该线程下还有子线程没有执行完毕才会结束,我们可以通过守护线程的方式,是的主线程执行完毕强制结束下面的子线程的运行


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

#!/usr/bin/env python3

# coding:utf-8

‘‘‘

Created on:

@author: 张晓宇

Email: [email protected]

Version: 1.0

Description: 守护线程演示程序

Help:

‘‘‘

import time

import threading

def child(n):

    ‘‘‘

    子线程执行的函数

    :param n:

    :return:

    ‘‘‘

    print(‘[%s]------running----\n‘ % n)

    time.sleep(2)

    print(‘--done--‘)

def main():

    ‘‘‘

    主线程要执行的函数

    :return:

    ‘‘‘

    for i in range(2): # 循环生成5个子线程

        t = threading.Thread(target=child,args=[i,])

        t.start()

        print(‘starting thread‘, t.getName())

m = threading.Thread(target=main,args=[]) # 创建主线程对象

m.setDaemon(True) #将主线程设置为Daemon线程,它退出时,其它子线程会同时退出,不管是否执行完任务

m.start() # 启动主线程

m.join() # 等待主线程执行完毕

print("---main thread done----")

输出结果


1

2

3

4

5

6

7

[0]------running----

starting thread Thread-2

[1]------running----

starting thread Thread-3

---main thread done----

可以看出,main线程下的子线程执行的时间要比main线程时间长,当main线程执行完的时候,子线程的print(‘--done--‘)还没有执行就被强制结束了


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

#!/usr/bin/env python

# coding:utf-8

‘‘‘

Created on:

@author: 张晓宇

Email: [email protected]

Version: 1.0

Description: 线程锁演示程序

Help:

‘‘‘

import threading

import time

def addNum():

    global num # 调用全局变量num

    print(‘--get num:‘, num)

    time.sleep(1)

    #lock.acquire()

    num += 1 # 每个线程都对num进行加1操作

    #lock.release()

    print(num)

if __name__ == ‘__main__‘:

    lock = threading.Lock()

    num = 0

    thread_list = [] # 初始化一个线程列表

    for i in range(10000): # 循环启动10000个进程

        t = threading.Thread(target = addNum)

        t.start()

        thread_list.append(t) # 加入到线程列表中

    for t in thread_list: # 循环等待线程列表里的所有线程结束

        t.join()

    print(num) # 打印num的最终值

正常情况,启动10000个线程,每个线程对num做加1操作,最终的结果将是10000,但是如果你用python2.X版本的解释器执行上面的代码会发现,最结果不总是10000,而且随着线程越多,这个最终结果的值稳定性越差,这就需要在对需要修改线程间共享的变量的时候加一把锁,当一个线程获得锁并操作一个共享变量的时候,其他线程只能等待锁释掉才可以,等待的过程是阻塞的,只有锁被释放掉,其他线程中“抢”到锁的进程才可以继续进行

申请锁


1

lock.acquire()

释放锁


1

lock.release()

注意,Python3.X已经修复了这个问题,不用加锁结果也是正确的

递归锁

递归锁说白了就是一个大锁里面套着小锁,也就是子锁,用到的地方不多,就不说了

信号量(Semaphore)

刚才说的锁也是互斥锁,同事只能有一个线程操作,而Semaphore可以同事允许一定数量的线程更改数据。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

import threading,time

 

def run(n):

    semaphore.acquire()

    time.sleep(1)

    print("run the thread: %s\n" %n)

    semaphore.release()

 

if __name__ == ‘__main__‘:

 

    num= 0

    semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行

    for i in range(20):

        t = threading.Thread(target=run,args=(i,))

        t.start()

 

while threading.active_count() != 1:

    pass #print threading.active_count()

else:

    print(‘----all threads done---‘)

    print(num)

事件Event

事件可以裂解为就是一个信号,他只有两个状态可以理解为真和假,常用方法如下

  • set():相当于设置为真
  • clear():相当于设置为假
  • isSet():判断是否为真
  • wait():等待事件置为真(阻塞)

?事件做常用的一个地方就是红绿灯模型,下面代码这就是演示红绿灯模型


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

#!/usr/bin/env python

# coding:utf-8

‘‘‘

Created on: 2016年3月5日

@author: 张晓宇

Email: [email protected]

Version: 1.0

Description: 红绿灯模型演示程序

Help:

‘‘‘

import threading

def light():

    ‘‘‘

    信号灯进程的线程执行的函数

    :return:

    ‘‘‘

    import time

    if not event.isSet(): # 判断是否为真,如果不为真就设置为真,也就是一上来是绿灯

        event.set()

    count = 0 # 初始化计数器,可以理解为红绿灯之间的等待时间

    while True: # 无限制循环下去

        if count < 10:

            # 0-10秒是绿灯

            print(‘\033[42;1m--green light on--\033[0m‘)

        elif count < 13:

            # 10-12是黄灯

            print(‘\033[43;1m--yellow light on--\033[0m‘)

        elif count < 20:

            # 14-19秒是红灯

            if event.isSet(): # 判断如果为真,就设置成假的

                event.clear()

            print(‘\033[41;1m--red light on--\033[0m‘)

        else:

            # 第20秒的时候计数器归零,并从新设置为真

            count = 0

            if not event.isSet():

                event.set()

        time.sleep(1)

        count += 1 # 计数器加1

def car(n):

    ‘‘‘

    汽车进程要执行的函数

    :param n:

    :return:

    ‘‘‘

    import time

    while True:

        time.sleep(1) # 每隔1秒检查一下红绿灯状态

        if event.isSet():

            # 如果为真就runing

            print(‘car [%s] is running...‘ %n)

        else:

            # 否则就waiting

            print(‘car [%s] is waiting for the red light...‘ %n)

            event.wait() # 等待事件变为真

if __name__ == ‘__main__‘:

    event = threading.Event() # 创建Event对象

    Light = threading.Thread(target = light) # 创建信号灯线程

    Light.start() # 启动线程

    for i in range(3): # 循环创建3个汽车线程对象,并启动

        t = threading.Thread(target = car, args = [i,])

        t.start()

时间: 2024-12-25 19:02:43

我的Python成长之路---第八天---Python基础(24)---2016年3月5日(晴)的相关文章

我的Python成长之路---第八天---Python基础(25)---2016年3月5日(晴)

多进程 multiprocessing模块 multiprocessing模块提供了一个Process类来代表一个进程对象 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 #!/usr/bin/env python3 # coding:utf-8 ''' Created on: 2016年3月5日 @author: 张晓宇 Email: [email protected] Versi

我的Python成长之路---第八天---Python基础(23)---2016年3月5日(晴)

socketserver 之前讲道德socket模块是单进程的,只能接受一个客户端的连接和请求,只有当该客户端断开的之后才能再接受来自其他客户端的连接和请求.当然我们也可以通过python的多线程等模块自己写一个可以同时接收多个客户端连接和请求的socket.但是这完全没有必要,因为python标准库已经为我们内置了一个多线程的socket模块socketserver,我们直接调用就可以了,完全没有必要重复造轮子. 我们只需简单改造一下之前的socket演示程序的服务端就可以了,客户端不用变 1

我的Python成长之路---第一天---Python基础(1)---2015年12月26日(雾霾)

2015年12月26日是个特别的日子,我的Python成之路迈出第一步.见到了心目中的Python大神(Alex),也认识到了新的志向相投的伙伴,非常开心. 尽管之前看过一些Python的视频.书,算是有一点基础.但在这里我要保持空杯心态,一切从头开始.好了不多说,Let's Python!!!! 一.Python简介 Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言.目前Python已经成为实际上除了中国最流行的开发语

我的Python成长之路---第一天---Python基础(2)---2015年12月26日(雾霾)

三.数据类型 Python基本类型(能够直接处理的数据类型有以下几种)主要有5种 1.整数(int) Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等. 2.浮点数(float) 浮点数也就是数学中的小数.由于整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的,而浮点数运算则可能会有四舍五入的误差.需要注意. 3.字符串 字符串是以单引号'或双引号"括起来的任意文本,比如'abc',"xy

我的Python成长之路---第一天---Python基础(6)---2015年12月26日(雾霾)

七.列表——list Python的列表是一种内置的数据类型,是由Python的基本数据类型组成的有序的集合.有点类似C语言的数组,但与数组不同的是,Python在定义列表的时候不用指定列表的容积(长度),可根据需要任意扩展,另外列表的内的元素可以是不同的数据类型,当然既然是任何数据类型,当然也包括另一个列表也就是嵌套.Python中列表使用中括号[]括起来,例如[1,2,True,'ABC',[5,'678']]. 1.列表的切片 通字符串一样列表也支持切片操作,例如我们有一个列表A_list

我的Python成长之路---第一天---Python基础(3)---2015年12月26日(雾霾)

四.变量和常量 变量是用来存储程序运行期间需要临时保存可以不断改变的数据的标识符.Python有自身的内存回收机制,所以在开发过程中不用考虑变量的销毁等 Python中的变量名命名有如下规则: 1.变量名必须是字母.数字和下划线的组合 2.数字不能开头 3.不能使用Python保留的关键字入print.id等(注意这个不是Python强制的,但是如果使用关键字定义了会是改变关键原来的用途) 关于变量名的一些建议: 1.变量名最好有意义,尽量不要使用a = 1, x = 'ABC',var = 1

我的Python成长之路---第二天---Python基础(8)---2016年1月9日(晴)

数据类型之字典 一.字典简介 字典dict(dictionary),在其他语言中也成为map,使用键-值(key-value)的形式存储和展现,具有极快的查找速度. 字典的定义 d = {'key':value,...} 字典可以嵌套,value也可以使用列表等数据类型 字典通过键获取键所对应的值 d[key] 二.字典常用方法 1.clear(清除字典所有元素) 代码: 1 def clear(self): # real signature unknown; restored from __d

我的Python成长之路---第一天---Python基础(作业1:登录验证)---2015年12月26日(雾霾)

1 #!/usr/bin/env python3 2 # coding:utf-8 3 ''' 4 Created on: 2015年12月29日 5 6 @author: 张晓宇 7 8 Email: [email protected] 9 10 Version: 1.0 11 12 Description: 输入用户名密码,认证成功显示欢迎信息,认证失败,输错三次后锁定 13 14 Help: 15 ''' 16 import os 17 # 定义用户信息写入函数,用于把用户信息写回文件 1

我的Python成长之路---第一天---Python基础(作业2:三级菜单)---2015年12月26日(雾霾)

#!/usr/bin/env python3 # coding:utf-8 ''' Created on: 2015年12月30日 @author: 张晓宇 Email: [email protected] Version: 1.0 Description: 三层菜单 1.菜单一共三级即:省,市,区县 2.每一级菜单输入的如果输入的是菜单里的选项则进入下级菜单 3.第1级菜单输入q退出系统 4.第2.3级菜单输入q退出系统,输入b返回上级菜单 5.三级菜单全部正确打印最后的全部选择结果,否则继续