多线程、多进程
进程:一个进程就是一个程序。
线程:线程就是进程里面最小的执行单元。
线程是在进程里面的,干活的还是线程。
一个进程里面最少有一个线程,可以有多个线程
每个线程之间都是互相独立的
没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。
串行:
1 import threading,time 2 def run(): 3 time.sleep(5) 4 print('哈哈哈哈') 7 for i in range(5):#串行 8 run()
多线程:
1 import threading,time 3 def run(name): 4 time.sleep(5) 5 print('【%s】哈哈哈哈'%name) 6 for i in range(10): 7 t=threading.Thread(target=run,args=(i,))#args传元组时,如果只有一个参数必须加一个逗号 8 t.start()
import threading import hashlib import requests def md5(msg): msg = str(msg) m = hashlib.md5(msg.encode()) return m.hexdigest() def down_load_pic(url): print('图片下载开始',url) r = requests.get(url) file_name = md5(url)+'.png' with open(file_name, 'wb') as fw: fw.write(r.content) print('%s图片下载完成'%file_name) urls = ['https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140'] for url in urls: t = threading.Thread(target=down_load_pic,args=[url]) t.start() while threading.active_count()!=1: pass print('所有照片已下载完成!')
获取不到返回值怎么办?return回来的返回值获取不到
import threading,time all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。 def run(name): time.sleep(5) print('【%s】哈哈哈哈'%name) name ='hhj'+name all_res.append(name) print(all_res) for i in range(10): t=threading.Thread(target=run,args=(str(i),))#args要传元组,如果只有一个参数必须加一个逗号 t.start()
等待子线程都执行完成再计时和返回字典:
方法1:
import threading,time all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。 def run(name): time.sleep(5) print('【%s】哈哈哈哈'%name) name ='hhj'+name all_res.append(name) for i in range(10): t=threading.Thread(target=run,args=(str(i),)) t.start() #主线程,线程之间是相互独立的 while threading.active_count()!=1:#判断当前活动的线程是几个,如果是1的话,说明子线程已经执行完成了 pass end = time.time() print(end-start) print('sleep之后的。。',all_res)
还有一种方法:
# t.join()#等待
1 import threading,time 2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。 3 def run(name): 4 time.sleep(5) 5 print('【%s】哈哈哈哈'%name) 6 name ='hhj'+name 7 all_res.append(name) 8 9 for i in range(10): 10 t=threading.Thread(target=run,args=(str(i),)) 11 threads.append(t) 12 t.start() 13 for t in threads:#再统一去等待子线程执行结束 14 t.join()#等待 15 end = time.time() 16 print(end-start) 17 print('sleep之后的。。',all_res)
查看线程的id
1 import threading,time 2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。 3 def run(name): 4 print('子线程执行的。。',threading.current_thread()) 5 time.sleep(5) 6 print('【%s】哈哈哈哈'%name) 7 name ='hhj'+name 8 all_res.append(name) 9 10 for i in range(3): 11 t=threading.Thread(target=run,args=(str(i),)) 12 threads.append(t) 13 t.start() 14 for t in threads:#再统一去等待子线程执行结束 15 t.join()#等待 16 17 print('主线程执行的。。', threading.current_thread()) 18 19 end = time.time() 20 print(end-start) 21 print('sleep之后的。。',all_res)
守护线程:
1 #守护线程 2 #守护线程就是和秦始皇陪葬的人一样 3 #主线程就是秦始皇 4 #子线程就是陪葬的人 5 import threading 6 import time 7 def run(): 8 time.sleep(9) 9 print('run...') 10 for i in range(10): 11 t = threading.Thread(target=run) 12 t.setDaemon(True)#设置子线程成为一个守护线程 13 t.start() 14 print('over.')
注释掉守护线程:
1 import threading 2 import time 3 def run(): 4 time.sleep(9) 5 print('run...') 6 for i in range(10): 7 t = threading.Thread(target=run) 8 # t.setDaemon(True)#设置子线程成为一个守护线程 9 t.start() 10 print('over.')
没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。
python里面的多线程,是利用不了多核cpu的,只能利用一个核心的cpu
有些情况下,你用多线程的时候会发现它比单线程速度还慢。
查看电脑的cpu是几核的:
锁:
import threading count = 0 lock = threading.Lock() def add(): global count for i in range(1000000): #法1 # lock.acquire()#加锁,线程安全;多线程的时候需要加锁,否则多个人修改同一条数据会报错 # count += 1 # lock.release() # 法2 with lock:#自动加锁自动释放 count += 1 for i in range(2): t = threading.Thread(target=add) t.start() while threading.active_count() != 1: pass print(count)
线程池
安装threadpool模块(pip install threadpool)
import threadpool,requests,pymongo client = pymongo.MongoClient(host='ip',port=27017) table = client['likun']['qq_group_likun'] all_qq = [i.get('qq') for i in table.find()] url = 'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140' def down_img(qq_num): res = requests.get(url%qq_num).content with open('%s.jpg'%qq_num,'wb') as fw: fw.write(res) pool = threadpool.ThreadPool(200)#线程池的大小 all_requests = threadpool.makeRequests(down_img,all_qq)#分配数据 for r in all_requests: pool.putRequest(r)#发请求 #[pool.putRequest(r) for r in all_requests]#同上两行 pool.wait()#等待所有的线程运行完 print('done,下载完成!')
import threadpool import threading import hashlib import requests import os def md5(msg): msg = str(msg) m = hashlib.md5(msg.encode()) return m.hexdigest() def down_load_pics(url): print(threading.current_thread()) print('图片下载开始',url) r = requests.get(url) pic_name = md5(url)+'.jpg' if not os.path.exists('pics'): os.system('mkdir pics') pic_name = os.path.join('pics',pic_name) with open(pic_name,'wb') as fw: fw.write(r.content) urls=['https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140', 'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140'] pool = threadpool.ThreadPool(2) reqs = threadpool.makeRequests(down_load_pics,urls)#传方法名和一个列表 for req in reqs: pool.putRequest(req) pool.wait() print('下载完成')
进程(进程里可以启动线程,也要加锁)
import multiprocessing import time def make_money(name): print('%s开始挣钱'%name) time.sleep(2) def start_process(): p = multiprocessing.Process(target=make_money,args=['zjr']) p.start() if __name__ == "__main__": start_process()
锁、多进程中加多线程
import multiprocessing import time import threading # lock = multiprocessing.Lock() def test(): print('多线程') def make_money(name): for i in range(10): t = threading.Thread(target=test)#多进程中加多线程 t.start() print('%s开始挣钱'%name) time.sleep(2) def start_process(): for i in range(5): p = multiprocessing.Process(target=make_money,args=['zjr']) p.start() print(multiprocessing.active_children()) while len(multiprocessing.active_children()) != 1: pass print('运行结束') if __name__ == "__main__": start_process()
进程池
1 from multiprocessing import Process, Pool, active_children 2 import pymongo,requests 3 client = pymongo.MongoClient(host='118.11.3.40',port=27017) 4 table = client['likun']['qq_group_likun'] 5 all_qq = [i.get('qq') for i in table.find()] 6 7 url = 'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140' 8 def down_img(qq_num): 9 res = requests.get(url%qq_num).content 10 with open('%s.jpg'%qq_num,'wb') as fw: 11 fw.write(res) 12 if __name__=='__main__':#必须写在这句底下,否则多进程用不了 13 for qq in all_qq: 14 # p = Process(target=down_img,args=(qq,)) 15 # p.start() 16 # print(active_children())#打印活动的进程数 17 pool = Pool(5)#指定进程池的大小 18 list(pool.map(down_img,all_qq))#运行,使用进程池 19 #map是个生成器
什么时候用多线程,什么时候用多进程?
cpu密集型任务:
消耗cpu比较多
排序、运算。。
io密集型任务
input/output
写文件、读文件
上传、下载
python的多线程是利用不了多核cpu的
全局解释器锁:GIL
多进程是可以利用多核cpu的