14 python学习笔记-多线程threading

做自动化测试时,测试的case多,单线程执行测试用例,速度慢,执行的时间长;或在使用Pyhotn或Java对服务端进行压力测试的时候,单线程只能模拟单个用户的行为,此时,我们可以引入多线程、多进程去执行测试用例,进行压力测试。
一、进程与线程基本概念

1、进程:

进程(英语:process),是指计算机中已运行的程序。你可以理解成一个任务就是一个进程,比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。进程是很多资源的集合。

2、线程

线程(英语:thread)是操作系统能够进行运算调度的最小单位,是进程里边具体干活的,它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程并行执行不同的任务。比如Word,它可以同时进行打字、拼写检查、打印等子任务,这些进程内的这些“子任务”称为线程(Thread)。

注:python中的多线程并不是真正意义上的多线程,因为python解释器使用了GIL的全局解释锁

GIL全局解释器锁:不能利用多核CPU,只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的,是因为操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。这个叫做上下文切换。

二、多线程threading

  • Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁.Threading模块封装了一些常用的方法,初学者直接学这个模块就行了。
  • Python中使用线程有两种方式:函数(函数式)或者用类(继承式、封装式)来包装线程对象
  • threading.Thread里面几个参数介绍:
    class Thread(_Verbose)
       
       __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None)
           
           *group*:group参数必须为空,参数group是预留的,用于将来扩展;
     
         参数args和kwargs分别表示调用target时的参数列表和关键字参数。
           
           *target*: 参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行
           
           *name*: 参数name是线程的名字。默认值为“Thread-N“,N是一个数字。
          
           *args*:传递给线程函数target的参数,他必须是个tuple类型.
           
           *kwargs*:kwargs表示关键字参数。字典类型 {}.

1、函数式多线程

下面是一个简单的函数式多线程:

 1 import threading
 2 
 3 #定义每个线程要运行的函数
 4 def down_load(num):
 5     print('等待下载完第%d个文件'%num)
 6 
 7 def music():
 8     print('听着音乐')
 9 
10 def eat(food,drink):
11     print('吃着%s,喝着%s'%(food,drink))
12 
13 if __name__ == '__main__':
14     #创建线程组
15     threads=[]
16     #创建线程t1,t2,t3
17     # 1、函数不传参数
18     t1=threading.Thread(target=music)
19     threads.append(t1)
20     # 2、传kwargs参数
21     t2=threading.Thread(target=eat,kwargs={'food':'炸鸡','drink':'可乐'})
22     threads.append(t2)
23     #3、带参数的用args传元组类型(参数最后多加一个逗号“,”要不然会报错)
24     t3 = threading.Thread(target=down_load,args=(1,))
25     threads.append(t3)
26 
27     #启动线程t3,t2,t1
28     for t in threads:
29         t.start()

=========执行结果==================

Thu Nov 21 23:56:36 2019听着音乐
Thu Nov 21 23:56:36 2019吃着炸鸡,喝着可乐
Thu Nov 21 23:56:36 2019等待下载完第1个文件

2、继承式多线程

下面是另一种启动多线程的方式,继承式

1.start()方法 开始线程活动。

对每一个线程对象来说它只能被调用一次,它安排对象在一个另外的单独线程中调用run()方法(而非当前所处线程)。

当该方法在同一个线程对象中被调用超过一次时,会引入RuntimeError(运行时错误)。

2.run()方法 代表了线程活动的方法。

你可以在子类中重写此方法。标准run()方法调用了传递给对象的构造函数的可调对象作为目标参数,如果有这样的参数的话,顺序和关键字参数分别从args和kargs取得
start()和run()方法的区别
 1 import threading,time
 2 
 3 
 4 #1.先写一个执行函数,用来实现做某件事情,不同的人在做不同的事用两个参数people,food。
 5 def cook(people,food):
 6     print('%s%s正在做%s'%(time.ctime(),people,food))
 7 
 8 
 9 #2.使用Threading模块创建线程,直接从threading.Thread继承,然后重写__init__方法和run方法
10 class MyThread(threading.Thread):#继承父类threading.Thread
11     def __init__(self,people,food,name):
12         '''重写threading.Thread初始化内容'''
13         threading.Thread.__init__(self)
14         self.threadName=name
15         self.people=people
16         self.food=food
17 
18     def run(self):  # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
19         '''重写run方法'''
20         print('开始线程:'+self.threadName)
21 
22         cook(self.people,self.food) #执行任务
23         print('等待中\n')
24         print('结束线程'+self.name)
25 
26 if __name__ == '__main__':
27     #创建新线程,并将线程添加到线程组
28     threads=[]
29     t1=MyThread('小米','红烧鱼','thread-1')
30     threads.append(t1)
31     t2=MyThread('小明','水煮牛肉','thread-2')
32     threads.append(t2)
33     t3=MyThread('小美','佛跳墙','thread-3')
34     threads.append(t3)
35 
36     #启动线程
37     for t in threads:
38         t.start()
39 
40     print(time.sleep(1))
41     print('退出主线程')

==============执行结果==============

开始线程:thread-1
Fri Nov 22 00:31:37 2019小米正在做红烧鱼
开始线程:thread-2
等待中

Fri Nov 22 00:31:37 2019小明正在做水煮牛肉
开始线程:thread-3
Fri Nov 22 00:31:37 2019小美正在做佛跳墙
等待中

结束线程Thread-3
退出主线程
结束线程Thread-1
等待中

结束线程Thread-2

从以上执行结果看,主线程已退出,子线程Thread-1和Thread-2还在运行,这就需要用到后面讲的等待线程和守护线程了

猜你喜欢

转载自www.cnblogs.com/cocomoly/p/11909390.html
今日推荐