python3的多线程很多人无法理解是怎么运行的,因此本文从程序猿的日常生活出发,写了一个由浅入深的多线程教程,这样子大家就不会觉得陌生了,多线程真的很简单很简单!
不要讲多线程局限于库或者框架,自己造轮子才是最大的快乐。
-----------------------------------------以下是正文--------------------------------------------
假设我是一个程序猿,我想听歌,但是我又要打码,所以有:
我听完歌就去打码:
1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 6 def matter1(music): 7 print("我想听这些歌") 8 9 for i in range(0,len(music)): 10 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 11 # 当前时间为 12 print(time.strftime('%Y%H%M%S', time.localtime())) 13 # 假设每一首歌曲的时间是2秒 14 time.sleep(2) 15 print("切换下一首歌...") 16 17 def matter2(number): 18 print("我在打码") 19 20 j = 0 21 while j <= number: 22 print("我准备写入第" + str(j + 1) +"行代码") 23 j = j + 1 24 # 当前时间为 25 print(time.strftime('%Y%H%M%S', time.localtime())) 26 # 假设每写一行代码的时间为1秒 27 time.sleep(1) 28 print("写下一行代码...") 29 30 if __name__ == '__main__': 31 32 start = time.time() 33 34 # 设定我要听的歌为 35 music = ["music1","music2","music3"] 36 # 开始听歌 37 matter1(music) 38 # 设定我要打码的行数 39 number = 5 40 # 开始打码 41 matter2(number) 42 43 end = time.time() 44 print("完成的时间为:" + str(end - start))
记录来的完成时间为:
完成的时间为:12.007483959197998
时间上完全符合,但是身为一个程序猿,可以一边打码一边听歌,那么设计一个多线程,让他们同时进行:
1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 import threading 6 7 def matter1(music): 8 print("我想听这些歌") 9 10 for i in range(0,len(music)): 11 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 12 # 当前时间为 13 print(time.strftime('%Y%H%M%S', time.localtime())) 14 # 假设每一首歌曲的时间是2秒 15 time.sleep(2) 16 print("切换下一首歌...") 17 18 def matter2(number): 19 print("我在打码") 20 21 j = 0 22 while j <= number: 23 print("我准备写入第" + str(j + 1) +"行代码") 24 j = j + 1 25 # 当前时间为 26 print(time.strftime('%Y%H%M%S', time.localtime())) 27 # 假设每写一行代码的时间为1秒 28 time.sleep(1) 29 print("写下一行代码...") 30 31 if __name__ == '__main__': 32 # 设定我要听的歌为 33 music = ["music1","music2","music3"] 34 35 # 设定我要打码的行数 36 number = 5 37 # 建立一个新数组 38 threads = [] 39 # 将听歌放入数组里面 40 thing1 = threading.Thread(target=matter1, args=(music,)) 41 threads.append(thing1) 42 # 将打码放入数组里面 43 thing2 = threading.Thread(target=matter2, args=(number,)) 44 threads.append(thing2) 45 46 # 开始时间 47 start = time.time() 48 # 写个for让两件事情都进行 49 for thing in threads: 50 # setDaemon为主线程启动了线程matter1和matter2 51 # 启动也就是相当于执行了这个for循环 52 thing.setDaemon(True) 53 thing.start() 54 55 # 结束时间 56 end = time.time() 57 print("完成的时间为:" + str(end - start))
但是直接就结束了?
完成的时间为:0.0010008811950683594
原来是setDaemon,主线程启动两个子线程后做事后,主线程就不管子线程是否运行完毕,直接往下运行,直接运行到
print("完成的时间为:" + str(end - start))
然后程序就结束了,因此,为了防止子线程还没结束主线程就结束的意外情况,在程序里面加个join:
1 import time 2 import threading 3 4 def matter1(music): 5 print("我想听这些歌") 6 7 for i in range(0,len(music)): 8 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 9 # 当前时间为 10 print(time.strftime('%Y%H%M%S', time.localtime())) 11 # 假设每一首歌曲的时间是2秒 12 time.sleep(2) 13 print("切换下一首歌...") 14 15 def matter2(number): 16 print("我在打码") 17 18 j = 0 19 while j <= number: 20 print("我准备写入第" + str(j + 1) +"行代码") 21 j = j + 1 22 # 当前时间为 23 print(time.strftime('%Y%H%M%S', time.localtime())) 24 # 假设每写一行代码的时间为1秒 25 time.sleep(1) 26 print("写下一行代码...") 27 28 if __name__ == '__main__': 29 # 设定我要听的歌为 30 music = ["music1","music2","music3"] 31 32 # 设定我要打码的行数 33 number = 5 34 # 建立一个新数组 35 threads = [] 36 # 将听歌放入数组里面 37 thing1 = threading.Thread(target=matter1, args=(music,)) 38 threads.append(thing1) 39 # 将打码放入数组里面 40 thing2 = threading.Thread(target=matter2, args=(number,)) 41 threads.append(thing2) 42 43 # 开始时间 44 start = time.time() 45 # 写个for让两件事情都进行 46 for thing in threads: 47 # setDaemon为主线程启动了线程matter1和matter2 48 # 启动也就是相当于执行了这个for循环 49 thing.setDaemon(True) 50 thing.start() 51 52 # 子线程没结束前主线程会被卡在这里 53 thing1.join() 54 thing2.join() 55 # 结束时间 56 end = time.time() 57 print("完成的时间为:" + str(end - start))
最后运行的时间就是打码的时间:
完成的时间为:6.003339052200317
这就真正做到了一边听歌一边打码的双手互博的状态,本文后面的那0.003333秒就别纠结了,系统运行程序花个0.0033333秒不过分吧
偷懒打码打4行:
number = 4 完成的时间为:5.008083820343018
------------------------------我是快乐的分割线------------------------------
网上的多线程都是写成“类”的形式,这里写成函数不符合“大众”标准,那么就改成类的形式:
1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 import threading 6 7 class MyThread(threading.Thread): 8 def __init__(self, func, args, name=''): 9 threading.Thread.__init__(self) 10 self.name = name 11 self.func = func 12 self.args = args 13 #self.counter = counter 14 15 def run(self): 16 # 某某线程要开始了 17 print(self.name + "开始了##################") 18 19 if self.name == "听歌线程": 20 matter1(music) 21 elif self.name == "打码线程": 22 matter2(number) 23 print(self.name + "结束了##################") 24 25 def matter1(music): 26 for i in range(0,len(music)): 27 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 28 # 假设每一首歌曲的时间是2秒 29 time.sleep(2) 30 print("切换下一首歌...") 31 32 def matter2(number): 33 j = 0 34 while j <= number: 35 print("我准备写入第" + str(j + 1) +"行代码") 36 j = j + 1 37 # 假设每写一行代码的时间为1秒 38 time.sleep(1) 39 print("写下一行代码...") 40 41 42 if __name__ == '__main__': 43 # 设定我要听的歌为 44 music = ["music1","music2","music3"] 45 46 # 设定我要打码的行数 47 number = 4 48 49 # 开始时间 50 start = time.time() 51 52 thing1 = MyThread(matter1, music,"听歌线程") 53 thing2 = MyThread(matter2, number, "打码线程") 54 thing1.start() 55 thing2.start() 56 thing1.join() 57 thing2.join() 58 59 # 结束时间 60 end = time.time() 61 print("完成的时间为:" + str(end - start))
运行结果也是6秒:
完成的时间为:6.001942157745361
----------------------我是快乐的分割线-------------------------
程序猿在跑代码的时候是很无聊的,无聊的时候就会想到去吃零食,那么我就加入一个函数:
1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 import threading 6 7 class MyThread(threading.Thread): 8 def __init__(self, func, args, name=''): 9 threading.Thread.__init__(self) 10 self.name = name 11 self.func = func 12 self.args = args 13 #self.counter = counter 14 15 def run(self): 16 # 某某线程要开始了 17 print(self.name + "开始了##################") 18 19 if self.name == "听歌线程": 20 matter1(music) 21 elif self.name == "打码线程": 22 matter2(number) 23 elif self.name == "零食线程": 24 matter3(snacks) 25 print(self.name + "结束了##################") 26 27 def matter1(music): 28 for i in range(0,len(music)): 29 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 30 # 假设每一首歌曲的时间是2秒 31 time.sleep(2) 32 print("切换下一首歌...") 33 34 def matter2(number): 35 j = 0 36 while j <= number: 37 print("我准备写入第" + str(j + 1) +"行代码") 38 j = j + 1 39 # 假设每写一行代码的时间为1秒 40 time.sleep(1) 41 print("写下一行代码...") 42 43 def matter3(snacks): 44 for k in range(0,len(snacks)): 45 print("我正在听着歌吃" + str(snacks[k]) + "零食") 46 #每吃一袋零食间隔5秒 47 time.sleep(5) 48 print("吃完了一包零食") 49 50 if __name__ == '__main__': 51 # 设定我要听的歌为 52 music = ["music1","music2","music3"] 53 54 # 设定我要打码的行数 55 number = 4 56 57 # 设定我想吃的零食 58 snacks = ["咪咪","辣条"] 59 60 # 开始时间 61 start = time.time() 62 63 thing1 = MyThread(matter1, music,"听歌线程") 64 thing2 = MyThread(matter2, number, "打码线程") 65 thing3 = MyThread(matter3, snacks, "零食线程") 66 thing1.start() 67 thing2.start() 68 thing3.start() 69 thing1.join() 70 thing2.join() 71 thing3.join() 72 73 # 结束时间 74 end = time.time() 75 print("完成的时间为:" + str(end - start))
程序运行的时间是:
完成的时间为:10.000968933105469
感觉还是吃零食比较耗时间。但是但是,程序猿只有两个手,那么吃零食和打码是不能同时进行了,那么这里加个线程锁:
1 #!/usr/bin/python3.4 2 # -*- coding: utf-8 -*- 3 4 import time 5 import threading 6 7 # 打开线程锁 8 lock = threading.Lock() 9 10 class MyThread(threading.Thread): 11 def __init__(self, func, args, name=''): 12 threading.Thread.__init__(self) 13 self.name = name 14 self.func = func 15 self.args = args 16 #self.counter = counter 17 18 def run(self): 19 # 某某线程要开始了 20 print(self.name + "开始了##################") 21 22 if self.name == "听歌线程": 23 matter1(music) 24 elif self.name == "打码线程": 25 matter2(number) 26 elif self.name == "零食线程": 27 matter3(snacks) 28 print(self.name + "结束了##################") 29 30 def matter1(music): 31 for i in range(0,len(music)): 32 print("第" + str(i + 1) + "首歌是:" + str(music[i])) 33 # 假设每一首歌曲的时间是2秒 34 time.sleep(2) 35 print("切换下一首歌...") 36 37 def matter2(number): 38 lock.acquire() 39 j = 0 40 while j <= number: 41 print("我准备写入第" + str(j + 1) +"行代码") 42 j = j + 1 43 # 假设每写一行代码的时间为1秒 44 time.sleep(1) 45 print("写下一行代码...") 46 lock.release() 47 48 def matter3(snacks): 49 lock.acquire() 50 for k in range(0,len(snacks)): 51 print("我正在听着歌吃" + str(snacks[k]) + "零食") 52 #每吃一袋零食间隔5秒 53 time.sleep(5) 54 print("吃完了一包零食") 55 lock.release() 56 57 if __name__ == '__main__': 58 # 设定我要听的歌为 59 music = ["music1","music2","music3"] 60 61 # 设定我要打码的行数 62 number = 4 63 64 # 设定我想吃的零食 65 snacks = ["咪咪","辣条"] 66 67 # 开始时间 68 start = time.time() 69 70 thing1 = MyThread(matter1, music,"听歌线程") 71 thing2 = MyThread(matter2, number, "打码线程") 72 thing3 = MyThread(matter3, snacks, "零食线程") 73 thing1.start() 74 thing2.start() 75 thing3.start() 76 thing1.join() 77 thing2.join() 78 thing3.join() 79 80 # 结束时间 81 end = time.time() 82 print("完成的时间为:" + str(end - start))
运行时间为:
完成的时间为:15.001857995986938
这里解释一下:
只是听歌和打码花的时间是5s多; 听歌、打码、吃零食同时进行是10s多;
加了线程锁后,打码和吃零食不能同时进行,那么就变成:
听歌和打码花的时间是5s多; 单独吃零食是10s多,加起来就是15秒;
为了验证吃零食的时候还是听着歌的,所以将听歌的时间间隔改成10s,得到的运行时间为:
完成的时间为:30.000711917877197
运行结果贴出来看一下:
1 听歌线程开始了################## 2 第1首歌是:music1 3 打码线程开始了################## 4 我准备写入第1行代码 5 零食线程开始了################## 6 写下一行代码... 7 我准备写入第2行代码 8 写下一行代码... 9 我准备写入第3行代码 10 写下一行代码... 11 我准备写入第4行代码 12 写下一行代码... 13 我准备写入第5行代码 14 写下一行代码... 15 打码线程结束了################## 16 我正在听着歌吃咪咪零食 17 切换下一首歌... 18 第2首歌是:music2 19 吃完了一包零食 20 我正在听着歌吃辣条零食 21 吃完了一包零食 22 零食线程结束了################## 23 切换下一首歌... 24 第3首歌是:music3 25 切换下一首歌... 26 听歌线程结束了##################
perfect!