一、什么是线程和进程
这个查了很多资料,最后我理解是这样的
进程:是 CPU 资源分配的最小单位,它主要用来就是资源的分配
线程:是 CPU 调度执行的最小单位,它主要用来系统调度
通俗的说我们电脑任务管理器中,运行的一个.exe文件,就是一个进程
启动一个进程,系统就要给他分配资源空间,比如说运行的内存神马滴,所以进程开多了,电脑就会卡,所以进程很耗系统资源
所以引出了线程,进程负责拿到资源分配,然后进程会起很多线程为他干活儿,比如微信,打开一个聊天是一个线程,打开两个聊天是启了两个线程,一个进程可以启很多个线程,这些线程共享一个进程的资源,所以线程更省资源,可以实现并发,但线程同样会受cpu调度
二、一般python多线程,我用到的场景
(1)想速度快的完成工作量比较大的工作,比如说爬去网页上的内容,内容比较多,我就会开启多线程去爬取
(2)在作一个任务的同时,还要同时做另一件事儿,两件事儿要并行,所以也会启动一个线程,像之前的文章,一方面在跑监控,一方面要有一个网页实时展示结果
https://www.jianshu.com/p/b2b6bb59bf14
三、现在开始我们来看一下多线程
(1)之前我们单线程的时代,我们干活儿是顺序的:
# -*-coding:utf-8-*-
import time
def feed_dog(name):
for i in range(0, 5):
print("I am feeding dog %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(2)
def feed_cat(name):
for i in range(0, 5):
print("I am feeding cat %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(5)
if __name__ == "__main__":
feed_dog("旺财")
feed_cat("咪咪")
print("主线程时间:%s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
输出结果是:
I am feeding dog 旺财 .......2021-11-10 11:18:45
I am feeding dog 旺财 .......2021-11-10 11:18:47
I am feeding dog 旺财 .......2021-11-10 11:18:49
I am feeding dog 旺财 .......2021-11-10 11:18:51
I am feeding dog 旺财 .......2021-11-10 11:18:53
I am feeding cat 咪咪 .......2021-11-10 11:18:55
I am feeding cat 咪咪 .......2021-11-10 11:19:00
I am feeding cat 咪咪 .......2021-11-10 11:19:05
I am feeding cat 咪咪 .......2021-11-10 11:19:10
I am feeding cat 咪咪 .......2021-11-10 11:19:15
主线程时间:2021-11-10 11:19:20
这是一个招描逗狗的时代,如果单线程,程序只能顺序执行,先逗完狗,再去逗猫
时间总共花了35秒
(2)现在我能干了,我的效率变高了,我就要一边招猫一边逗狗,两样一起干
所以我们要启用多线程,两件事儿一起干
# -*-coding:utf-8-*-
import threading
import time
def feed_dog(name):
for i in range(0, 5):
print("I am feeding dog %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(2)
def feed_cat(name):
for i in range(0, 5):
print("I am feeding cat %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(5)
if __name__ == "__main__":
t_dog = threading.Thread(target=feed_dog,args=("旺财",)) #创建线程
t_cat = threading.Thread(target=feed_cat, args=("咪咪",) ) #创建线程
threads = [t_cat,t_dog] #把多个线程放一个数组里
for thread in threads:
thread.start() #依次启动线程
for thread in threads:
thread.join() #用于等待线程终止
print("主线程时间:%s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
输出结果是
I am feeding cat 咪咪 .......2021-11-10 11:25:14
I am feeding dog 旺财 .......2021-11-10 11:25:14
I am feeding dog 旺财 .......2021-11-10 11:25:16
I am feeding dog 旺财 .......2021-11-10 11:25:18
I am feeding cat 咪咪 .......2021-11-10 11:25:19
I am feeding dog 旺财 .......2021-11-10 11:25:20
I am feeding dog 旺财 .......2021-11-10 11:25:22
I am feeding cat 咪咪 .......2021-11-10 11:25:24
I am feeding cat 咪咪 .......2021-11-10 11:25:29
I am feeding cat 咪咪 .......2021-11-10 11:25:34
主线程时间:2021-11-10 11:25:39
我启动了两个线程,同时做两件事情,我的时间节省了10秒,用了25秒的时间
首先启动多线程要引入threading
import threading
join函数是等待线程中止,说白了就是启动的线程的事儿干完了,再干主线程的活儿,我理解主线程就是main函数中,除了thread启动的以外的线程,比如说上面的
print("主线程时间:%s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
for thread in threads:
thread.join()
所以上面的线程都执行完了,再执行了输出主线程时间的语句
那其实一些场景,我们不需要前面有对主线程的阻塞,我们需要主线程和启动的线程一起干活儿,但是主线程结束了,其他启动的线程也要跟着结束,所以我们要用到一个方法,这个方法一定要写在start()前面,他会把启动的线程设为主线程的守护线程,守护线程启动后,就去干他的活儿了,代码会接着往后跑,不会阻塞主线程
t.setDaemon(True)
我们再来改一下代码
import threading
import time
def feed_dog(name):
for i in range(0, 5):
print("I am feeding dog %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(2)
def feed_cat(name):
for i in range(0, 5):
print("I am feeding cat %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(5)
if __name__ == "__main__":
t_dog = threading.Thread(target=feed_dog,args=("旺财",))
t_cat = threading.Thread(target=feed_cat, args=("咪咪",) )
threads = [t_cat,t_dog]
for thread in threads:
thread.setDaemon(True)
thread.start()
print("主线程时间:%s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
输出结果是:
I am feeding cat 咪咪 .......2021-11-10 12:06:00
I am feeding dog 旺财 .......2021-11-10 12:06:00
主线程时间:2021-11-10 12:06:00
从结果可以看出,t_dog , t_cat启动后,并没有阻塞主线程,因为主线程只输出一句话,所以很快就运行完了,主线程结束后,守护线程也就没有接着往下运行,同时也就结束了
同理,之前写的
https://www.jianshu.com/p/b2b6bb59bf14
监控的同时,显示结果的网页也在同时刷新结果,但是我监控一旦停止了,你的结果网页显示也就没意义了,所以也要停止,用的就是这种方式
我们再把代码改的明显点:
# -*-coding:utf-8-*-
import threading
import time
def feed_dog(name):
for i in range(0, 5):
print("I am feeding dog %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(2)
def feed_cat(name):
for i in range(0, 5):
print("I am feeding cat %s .......%s" % (name,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
time.sleep(5)
if __name__ == "__main__":
t_dog = threading.Thread(target=feed_dog,args=("旺财",))
t_cat = threading.Thread(target=feed_cat, args=("咪咪",) )
threads = [t_cat,t_dog]
for thread in threads:
thread.setDaemon(True)
thread.start()
for i in range(0,5):
time.sleep(1)
print("主线程时间:%s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
输出结果
I am feeding cat 咪咪 .......2021-11-10 12:10:42
I am feeding dog 旺财 .......2021-11-10 12:10:42
主线程时间:2021-11-10 12:10:43
I am feeding dog 旺财 .......2021-11-10 12:10:44
主线程时间:2021-11-10 12:10:44
主线程时间:2021-11-10 12:10:45
I am feeding dog 旺财 .......2021-11-10 12:10:46
主线程时间:2021-11-10 12:10:46
I am feeding cat 咪咪 .......2021-11-10 12:10:47
主线程时间:2021-11-10 12:10:47
Process finished with exit code 0
这个很是显了吧,守护线程没有阻塞主线程,两个线程一起在做各自的事情,但主线程一旦结束,子线程不管做没做完,都会跟着结束