python 多线程
2022-04-05 16:52 jym蒟蒻 阅读(80) 评论(0) 编辑 收藏 举报python threading-单线程 多线程 主线程 子线程 setDeamon join
- 单线程
- 多线程
- 主线程和子线程
- setDaemon()
- join()
- 测试多线程下程序运行的时间
- 创建多个线程
- 优化子线程
用单线程 ,做听音乐和看电影两件事儿,首先排一下顺序。
import time
def music():
for i in range(2):
print("I was listening to music. %s" %time.ctime())
time.sleep(1)
def move():
for i in range(2):
print("I was at the movies. %s" %time.ctime())
time.sleep(5)
if __name__=='__main__':
music()
move()
print("all over %s" %time.ctime())
输出结果:
I was listening to music. Wed Oct 20 15:42:19 2021
I was listening to music. Wed Oct 20 15:42:20 2021
I was at the movies. Wed Oct 20 15:42:21 2021
I was at the movies. Wed Oct 20 15:42:26 2021
all over Wed Oct 20 15:42:31 2021
time.sleep(1)是延时1s的意思。我们先听了一首音乐,通过for循环来控制音乐的播放了两次,每首音乐播放需要1秒钟,sleep()来控制音乐播放的时长。接着我们又看了一场电影,每一场电影需要5秒钟,通过for循环看两遍。在整个结束后,输出当前的时间。
可以发现:整个代码只能是先干一件事再干一件事。
用时:开始42分19结束是42分31,总耗时为12s。
cpu同时干多个活都没问题的,不需要让一件事一直占着cpu不放;于是,操作系统就进入了多任务时代。
python提供了threading模块来实现多线程。可以 引入threadring来同时播放音乐和视频。
import threading
import time
def music():
for i in range(2):
print("I was listening to music. %s" %time.ctime())
time.sleep(1)
def move():
for i in range(2):
print("I was at the movies. %s" %time.ctime())
time.sleep(5)
'''
创建了threads数组,创建线程t1,使用threading.Thread()方法,
在这个方法中调用music方法target=music,
把创建好的线程t1装到threads数组中。
接着以同样的方式创建线程t2,并把t2也装到threads数组。
'''
threads = []
t1 = threading.Thread(target=music)
threads.append(t1)
t2 = threading.Thread(target=move)
threads.append(t2)
if __name__=='__main__':
for t in threads:
t.setDaemon(True)
t.start()
print("all over %s" %time.ctime())
主线程:是执行主(main)方法的线程.
子线程:被Thread包含的“方法体”或者“委托”均为子线程
当启动一个线程时设置thread.setDaemon(True),则该线程为守护线程(也可以称为后台线程)。表示该线程是不重要的,进程退出时不需要等待这个线程执行完成。这样做的意义在于:避免子线程无限死循环,导致退不出程序,也就是避免了孤儿进程的出现。
当不设置或者thread.setDaemon(False)时,主进程执行结束时,会等待线程结束。
上述程序如果设置t.setDaemon(False),那么将输出:
I was listening to music. Wed Oct 20 16:11:27 2021
I was at the movies. Wed Oct 20 16:11:27 2021
all over Wed Oct 20 16:11:27 2021
I was listening to music. Wed Oct 20 16:11:28 2021
I was at the movies. Wed Oct 20 16:11:32 2021
可以看到,在主线程进行完之后,也就是输出all over Wed Oct 20 16:11:27 2021之后,还会继续执行没完成的子线程。
如果设置setDaemon(True),那么将输出:
I was listening to music. Wed Oct 20 16:03:27 2021
I was at the movies. Wed Oct 20 16:03:27 2021
all over Wed Oct 20 16:03:27 2021
也就是说,子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print(“all over %s” %time.ctime())后,没有等待子线程,直接就退出了,同时子线程也一同结束。
import threading
import time
def music():
for i in range(2):
print("I was listening to music. %s" %time.ctime())
time.sleep(1)
def move():
for i in range(2):
print("I was at the movies. %s" %time.ctime())
time.sleep(5)
threads = []
t1 = threading.Thread(target=music)
threads.append(t1)
t2 = threading.Thread(target=move)
threads.append(t2)
if __name__=='__main__':
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join()
print("all over %s" %time.ctime())
运行结果:
I was listening to music. Wed Oct 20 16:21:41 2021
I was at the movies. Wed Oct 20 16:21:41 2021
I was listening to music. Wed Oct 20 16:21:42 2021
I was at the movies. Wed Oct 20 16:21:46 2021
all over Wed Oct 20 16:21:51 2021
我们只对上面的程序加了个join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
也就是说,必须等待for循环里的两个进程都结束后,才去执行主进程。
从执行结果可看到,music 和move 是同时启动的。
开始时间21分41秒,结束时间为21分51秒,总耗时为10秒。比单线程用时减少了2秒。
现在把music的sleep()的时间调整为5秒。
import threading
import time
def music():
for i in range(2):
print("I was listening to music. %s" %time.ctime())
time.sleep(5)
def move():
for i in range(2):
print("I was at the movies. %s" %time.ctime())
time.sleep(5)
threads = []
t1 = threading.Thread(target=music)
threads.append(t1)
t2 = threading.Thread(target=move)
threads.append(t2)
if __name__=='__main__':
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join()
print("all over %s" %time.ctime())
I was listening to music. Wed Oct 20 16:41:59 2021
I was at the movies. Wed Oct 20 16:41:59 2021
I was listening to music. Wed Oct 20 16:42:04 2021
I was at the movies. Wed Oct 20 16:42:04 2021
all over Wed Oct 20 16:42:09 2021
可以看到,最后还是用时10s。
如果是用单线程的话,用时将达到5*4=20s。
从上面例子中发现线程的创建是颇为麻烦的,每创建一个线程都需要创建一个tx(t1、t2、…),如果创建的线程多时候这样极其不方便。下面对通过例子进行继续改进:
import threading
import time
def music(func):
for i in range(2):
print("Start music: %s! %s" % (func, time.ctime()))
time.sleep(5)
def move(func):
for i in range(2):
print("Start playing: %s! %s" % (func, time.ctime()))
time.sleep(5)
'''
创建了一个player()函数,这个函数用于判断播放文件的类型。如果是mp3格式的,我们将调用music()函数,如果是mp4格式的我们调用move()函数。哪果两种格式都不是那么只能告诉用户你所提供有文件我播放不了
'''
def player(name):
r = name.split('.')[1]
if r == 'mp3':
music(name)
else:
if r == 'mp4':
move(name)
else:
print("ERROR:The format is not recognized!")
'''
创建了一个list的文件列表,注意为文件加上后缀名。然后我们用len(list) 来计算list列表有多少个文件,这是为了帮助我们确定循环次数。
'''
list = ['jjj.mp3', 'yyy.mp4']
threads = []
files = range(len(list))
'''
通过一个for循环,把list中的文件添加到线程中数组threads[]中。
'''
for i in files:
t = threading.Thread(target=player, args=(list[i],))
threads.append(t)
'''
启动threads[]线程组,最后打印结束时间。
'''
if __name__ == '__main__':
for i in files:
threads[i].start()
for t in files:
threads[i].join()
print("all over %s" %time.ctime())
运行结果:
Start music: jjj.mp3! Wed Oct 20 17:04:49 2021
Start playing: yyy.mp4! Wed Oct 20 17:04:49 2021
Start playing: yyy.mp4! Wed Oct 20 17:04:54 2021
Start music: jjj.mp3! Wed Oct 20 17:04:54 2021
all over Wed Oct 20 17:04:59 2021
其中,split()可以将一个字符串拆分成两部分,然后取其中的一部分。也就是说,判断list[i]里面后缀是mp3还是mp4类型的。
>>> x = 'testing.py'
>>> s = x.split('.')[1]
>>> if s=='py':
print(s)
py
现在向list数组中添加一个文件,程序运行时会自动为其创建一个线程。
我们发现player()用于判断文件扩展名,然后调用music()和move() ,其实,music()和move()工作是类似的,可以改进一下,不管什么文件都可以播放。
import threading
import time
'''
创建player()函数,用于接收file和t,用于确定要播放的文件及时长。
'''
def player(file, t):
for i in range(2):
print("Start playing: %s! %s" % (file, time.ctime()))
time.sleep(t)
'''
字典list ,用于定义要播放的文件及时长(秒),通过字典的items()方法来循环的取file和t,取到的这两个值用于创建线程。
'''
list = {'jjj.mp3': 3, 'yyy.mp4': 5, 'mmm.mp3': 4}
threads = []
files = range(len(list))
for file, t in list.items():
tx = threading.Thread(target=player, args=(file, t))
threads.append(tx)
if __name__ == '__main__':
for i in files:
threads[i].start()
for t in files:
threads[i].join()
print("all over %s" %time.ctime())
运行结果:
Start playing: jjj.mp3! Wed Oct 20 17:50:43 2021
Start playing: yyy.mp4! Wed Oct 20 17:50:43 2021
Start playing: mmm.mp3! Wed Oct 20 17:50:43 2021
Start playing: jjj.mp3! Wed Oct 20 17:50:46 2021
Start playing: mmm.mp3! Wed Oct 20 17:50:47 2021
Start playing: yyy.mp4! Wed Oct 20 17:50:48 2021
all over Wed Oct 20 17:50:51 2021