一文看懂python多线程

程序、进程及线程的区别

计算机程序是磁盘中可执行的二进制数据(或者其他类型)他们只有在被读取到内存中,被操作系统调用才开始他们的生命周期。

进程是程序的一次执行,每个进程都有自己的地址空间,内存,数据栈,以及其他记录其运行轨迹的辅助数据,操作系统管理再其上面运行的所有进程,并为这些进程公平得分配时间。

线程与进程相似,不同的是所有的线程都运行在同一个进程中,共享相同的运行环境。

 

1.单线程

单线程时,当处理器需要处理多个任务时,必须对这些任务安排执行的顺序,并按照这个顺序来执行任务。

 from time import sleep, ctime
  
  
  # 听音乐
  def music():
      print('i was listening to music! %s' % ctime())
      sleep(2)
  
  
 # 看电影
 def movie():
     print('i was at the movies! %s' % ctime())
     sleep(5)
 
 
 if __name__ == '__main__':
     music()
     movie()
     print('all end:', ctime())

增加循环功能:

 from time import sleep, ctime
  
  
  # 听音乐
  def music(func, loop):
      for i in range(loop):
          print('i was listening to music! %s !%s' % (func, ctime()))
            sleep(2)
  
 
 # 看电影
 def movie(func, loop):
     for i in range(loop):
         print('i was listening to music! %s !%s' % (func, ctime()))
         sleep(5)
 
 
 if __name__ == '__main__':
     music('爱情买卖', 2)
     movie('一代宗师', 2)
     print('all end:', ctime())

 

给music()和movie()两个函数设置参数:播放文件和播放次数。函数中通过for循环控制播放的次数。

2、多线程

python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的,原始的线程以及一个简单的锁。threading基于Java的线程模型设计。锁(lock)和条件变量(condition)在Java中时对象的基本行为(每个对象都自带了锁和条件变量),而在python中则是独立的对象。

(1)threading模块

避免使用thread模块,原因是它不支持守护线程。当主线程退出时,所有的子线程不关他们是否还在工作,都会被强行退出。但是我们并不希望发生这种行为。就要引入守护线程的概念。threading支持守护线程。

 from time import sleep, ctime
 import threading
  
  
  # 听音乐
  def music(func, loop):
      for i in range(loop):
          print('i was listening to music! %s !%s' % (func, ctime()))
          sleep(2)
 
 
 # 看电影
 def movie(func, loop):
     for i in range(loop):
         print('i was listening to music! %s !%s' % (func, ctime()))
         sleep(5)
 
 
 # 创建线程数组
 threads = []
 # 创建线程t1,并添加到线程数组
 t1 = threading.Thread(target=music, args=('爱情买卖', 2))
 threads.append(t1)
 # 创建线程t2,并添加到线程数组
 t2 = threading.Thread(target=music, args=('一代宗师', 2))
 threads.append(t2)
 
 if __name__ == '__main__':
     # 启动线程
     for t in threads:
         t.start()
     # 守护线程
     for t in threads:
         t.join()
 
     print('all end:', ctime())

注:import threading: 引入线程模块

       threads = []:创建线程数组,用于装载线程。

       threading.Thread(): 通过调用threading模块的Thread()方法来创建线程。

运行结果如下:

一文看懂python多线程_第1张图片

从上面运行的结果可以看出,两个子线程(music,movie)同时启动于10分15秒,知道所有线程结束于10分17秒共好使2秒。从执行的结果可以看出两个线程达到了并行工作。

优化线程的创建

从上面例子中发现线程的创建很麻烦,每创建一个线程都需要一个t(t1,t2.。。。。)当创建的线程较多时,这样的操作及其的不方便。

 

 from time import sleep, ctime
 import threading
  
  
  # 创建超级播放器
  def super_player(file_, loop):
      for i in range(2):
          print('start playing: %s !%s' % (file_, ctime()))
          sleep(2)
 # 播放文件与播放时长
 lists = {'爱情买卖.mp3':3,'阿凡达.mp4':5,'传奇.mp3':4}
 
 threads = []
 files = range(len(lists))
 print(files)
 # 创建线程
 print(lists.items())
 for file_,time in lists.items():
     t = threading.Thread(target=super_player,args=(file_,time))
     print(t)
     threads.append(t)
 
 if __name__ == '__main__':
     # 启动线程
     for t in files:
         threads[t].start()
     # 守护线程
     for t in files:
         threads[t].join()
 
     print(' end:%s'% ctime())

 

 一文看懂python多线程_第2张图片

 

  from time import sleep, ctime
  import threading
  
  
  # 创建超级播放器
  def super_player(file_, loop):
      for i in range(3):  # 控制线程的循环次数
          print('start playing: %s !%s' % (file_, ctime()))
          sleep(3)  # 每次循环的间接次数
 
 
 # 播放文件与播放时长
 lists = {'爱情买卖.mp3': 3, '阿凡达.mp4': 5, '传奇.mp3': 4}
 
 threads = []
 files = range(len(lists))
 print(len(lists))
 
 print(files)  # 打印的结果是range(0,3)
 # 创建线程
 print(lists.items())
 for file_, time in lists.items():
     t = threading.Thread(target=super_player, args=(file_, time))
     print(t)
     threads.append(t)
 
 if __name__ == '__main__':
     # 启动线程
     for t in files:
         threads[t].start()
     # 守护线程
     for t in files:
         threads[t].join()
 
     print(' end:%s' % ctime())

 

 创建了一个super_player()函数,这个函数可以接收播放文件和播放时长,可以播放任何文件。

创建了一个lists字典用于存放播放文件名与时长,通过for循环读取字典,并调用super_play()函数创建字典,接着将创建的字典都追加到threads数组中。

最后通过循环启动线程数组threads中的线程。

 

创建线程类

 

  import threading
  from time import sleep, ctime
  
 
  # 创建线程类
   class MyThread (threading.Thread):
      def __init__(self, func, args, name=''):
          threading.Thread.__init__ (self)
          self.func = func
         self.args = args
         self.name = name
 
     def run(self):
         self.func (*self.args)
 
 
 # 创建超级播放器
 def super_player(file_, loop):
     for i in range (3):  # 控制线程的循环次数
         print ('start playing: %s !%s' % (file_, ctime ()))
         sleep (3)  # 每次循环的间接次数
 
 
 # 播放文件与播放时长
 lists = {'爱情买卖.mp3': 3, '阿凡达.mp4': 5, '传奇.mp3': 4}
 
 threads = []
 files = range (len (lists))
 print (len (lists))
 
 print (files)  # 打印的结果是range(0,3)
 # 创建线程
 print (lists.items ())
 for file_, time in lists.items ():
     t = threading.Thread (target=super_player, args=(file_, time))
     print (t)
     threads.append (t)
 
 if __name__ == '__main__':
     # 启动线程
     for t in files:
         threads[t].start ()
     # 守护线程
     for t in files:
         threads[t].join ()
 
     print (' end:%s' % ctime ())

 

MyThread(threading.Thread)

创建MyThread类,用于继承threading.Thread类

__init__()类的初始化方法对func,args,name等参数进行初始化。

self.func (*self.args)函数的作用是当函数参数已经存在于一个元组或者字典中时,apply()间接地调用函数。args是一个包含将要提供给函数的按位置传递的参数元组。
如果省略了args,则任何参数不会被传递,kwargs是一个包含关键字参数的字典

结语

对测试技术感兴趣的同学,欢迎加QQ群175317069,一起学习,相互讨论。

群内已经有小伙伴将知识体系整理好(源码,笔记,PPT,学习视频),欢迎加群免费领取

加QQ群175317069,免费领取资料

你可能感兴趣的:(软件测试)