一、what线程,what进程
1、进程
是资源的整合。一个程序对于操作系统来说就是一个进程、例如打开浏览器、打开word等都是打开一个进程。
2、线程
是程序里面的最小执行单元。帮助进程干活的,线程之间相互独立
多线程多用于处理IO密集型任务频繁写入读出,cpu负责调度,消耗的是磁盘空间
3、线程是包含在一个进程里面的,一个进程可以有多个线程
4、一个进程里面默认有一个线程
5、主线程与子线程,一个程序默认有一个主线程,由主线程来启动子线程
导入模块
import threading
传统方式(单线程)
串行
def down_load(): time.sleep(5) print('运行完成') for i in range(3): down_load()
多线程方式
并行
for i in range(3): t=threading.Thread(target=down_load) #实例化一个线程 t.start() #开始运行
down_load不要带(),不然属于自己调用了
线程之间相互独立
t1=time.time()
for i in range(3):
t=threading.Thread(target=down_load) #实例化一个线程
t.start() #开始运行
print('运行时间',time.time()-t1)
上面的代码,总共有4个线程,循环里面启动了3个线程,还有一个主线程在运行所以结果如下
主线程运行结束打印运行时间,后等待子线程结束
运行时间 0.0009999275207519531
运行完成
运行完成
运行完成
查看当前线程数和线程
print(threading.active_count()) #查看 线程数 print(threading.current_thread()) #查看 当前线程
主线程等待子线程结束(并行)
def down_load(): time.sleep(5) print('运行完成') # 多线程 t1=time.time() for i in range(3): t=threading.Thread(target=down_load) t.start() # t.join() #这里是树形结构不是并行结构 # t.join() #这里等待的是最后一个线程结束的时间 while threading.activeCount()!=1: #主线程等待子线程结束 pass
多线程下载图片
import requests,threading,time from hashlib import md5 def down_load_pic(url): req=requests.get(url) m=md5(url.encode()) with open(m.hexdigest()+'.png','wb') as fw: fw.write(req.content) url_list=['http://url.cn/Tfhpen?.jpg', 'http://www.nnzhp.cn/wp-content/uploads/2019/11/542824dde1dbd29ec61ad5ea867ef245.png' 'http://www.nnzhp.cn/wp-content/uploads/2019/10/5901238e6ec4a53bfd17e68762c3403a.png', 'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png'] t1=time.time() for url in url_list: t= threading.Thread(target=down_load_pic,args=(url,)) t.start() while threading.activeCount()!=1: pass #并行下载时间哪个最长,就是哪个时间 print('运行时间:',time.time()-t1)
守护线程
import yagmail,threading def send_mail(): smtp=yagmail.SMTP(host='smtp.126.com', user='newcwl@126.com', password='KVXLMGVQZUZPPZBK' ) smtp.send(to='526962645@qq.com',cc=[],subject='测试python邮箱发送内容', contents='正文是:"hahahahahhahahaha"',attachments=[]) # 如果由于网络或者其他原因导致发送缓慢,而主线程没有等待执行完毕 def async_send_mail(): t=threading.Thread(target=send_mail) t.start() # 这里专门启动了一个线程来发邮件 # 不用等着了
线程池(根据指定的线程池大小自动分发数据)(数据量大的时候应用)
import requests,threadpool from hashlib import md5 def down_load_pic(url): req=requests.get(url) m=md5(url.encode()) with open(m.hexdigest()+'.png','wb') as fw: fw.write(req.content) url_list=['http://www.nnzhp.cn/wp-content/uploads/2019/07/mysql.jpeg', 'http://url.cn/Tfhpen?.jpg', 'http://www.nnzhp.cn/wp-content/uploads/2019/03/js.png', 'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png'] pool=threadpool.ThreadPool(8) #实例化线程池(指定大小) reqs=threadpool.makeRequests(down_load_pic,url_list)#分配数据(第一个参数是函数,第二个参数是数据) [pool.putRequest(req) for req in reqs] pool.wait() #等待 print('end')
守护线程(陪葬的)
只要主线程结束,守护线程立即结束,不管子线程有没有结束
import threading,time def down_load(): time.sleep(4) print('运行结束') for i in range(10): t=threading.Thread(target=down_load) t.setDaemon(True) #设置子线程为守护线程 t.start() print('over')
获取线程返回值
import requests,threading,time,threadpool from hashlib import md5 result={} def down_load_pic(url): req=requests.get(url) m=md5(url.encode()) file_name=m.hexdigest()+'.png' with open(file_name,'wb') as fw: fw.write(req.content) result[file_name]=threading.current_thread() #获取线程返回值 return result url_list=['http://www.nnzhp.cn/wp-content/uploads/2019/07/mysql.jpeg', 'http://url.cn/Tfhpen?.jpg', 'http://www.nnzhp.cn/wp-content/uploads/2019/03/js.png', 'http://www.nnzhp.cn/wp-content/uploads/2019/10/d4b1c8df4d101f531ec2f837ed787e17.png'] t1=time.time() for url in url_list: t= threading.Thread(target=down_load_pic,args=(url,)) t.start() while threading.activeCount()!=1: pass #并行下载时间哪个最长,就是哪个时间 print('运行时间:',time.time()-t1) print(result)
锁
线程锁,线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据。
import threading num=0 lock=threading.Lock() def add(): global num # lock.acquire() #加锁 # num+=1 # lock.release() #解锁 (如果不解锁,就会产生死锁程序运行到这无法执行) with lock: #简写,同注释部分一样 num+=1 for i in range(20): t=threading.Thread(target=add,) t.start() while threading.activeCount()!=1: pass print(num)
多进程
import multiprocessing,time def down_load(): time.sleep(5) print('运行完了') if __name__ == '__main__':#必须加这个才能启动多进程 for i in range(5): p = multiprocessing.Process(target=down_load) p.start() while len(multiprocessing.active_children())!=0:#等待子进程结束 pass # print(multiprocessing.active_children()) # print(multiprocessing.current_process()) print('end')
1、如果是CPU密集型代码(循环、计算等),由于计算工作量多和大,计算很快就会达到100,然后触发GIL的释放与在竞争,多个线程来回切换损耗资源,所以在多线程遇到CPU密集型代码时,单线程会比较快;
算法,计算、数据分析,等不和磁盘打交道的
2、如果是IO密集型代码(文件处理、网络爬虫),开启多线程实际上是并发(不是并行),IO操作会进行IO等待,线程A等待时,自动切换到线程B,这样就提升了效率。
磁盘io、网络io、input、output