进程
进程的 两关系一特点 :
子进程.join() 来 阻塞主进程:
1 from multiprocessing import Process 2 3 def test(*args,**kwargs): 4 print("{}邮件已经发送完毕...".format(args[0])) 5 6 if __name__ == "__main__": 7 process_lists = [] 8 for i in range(10): 9 process_lists.append(Process(target=test,args=(i,))) 10 11 for process in process_lists: 12 process.start() 13 14 for process in process_lists: #此时 主进程 只有在 所以子进程之后才会执行! 15 process.join() 16 17 print("邮件发送完毕!") 18 19 20
第二种,使用面向对象方式 开启子进程:
1 from multiprocessing import Process 2 import os 3 4 class MyProcess(Process): 5 def run(self): 6 print("我是子进程,我的id是:",os.getpid(),"我的父亲的id 是 ",os.getppid()) 7 8 if __name__ == "__main__": 9 # 第一种 开启子进程的第一种方式 是用target= args= kwargs= 等! 10 # 下面看第二种: 使用面向对象的方法 11 MyProcess().start() 12 13 print("我是主进程,我的id 是",os.getpid()) 14 ''' 15 MyProcess().start() 中的.start() 做了两件事: 16 1, 开启子进程。 17 2, 让子进程执行 run 中的方法。 18 '''
使用面向对象方式,如何给子进程 传递参数:
1 from multiprocessing import Process 2 import os 3 class MyProcess(Process): 4 def __init__(self,*args,**kwargs): 5 super().__init__() 6 print(args) 7 print(kwargs) 8 def run(self): 9 print("我是子进程,我的id是:", os.getpid(), "我的父亲的id 是 ", os.getppid()) 10 11 12 if __name__ == "__main__": 13 # 第一种 开启子进程的第一种方式 是用target= args= kwargs= 等! 14 # 下面看第二种: 使用面向对象的方法 15 MyProcess(1,2,name="tom",age=19).start() 16 print("我是主进程,我的id 是", os.getpid()) 17 ''' 18 MyProcess().start() 中的.start() 做了两件事: 19 1, 开启子进程。 20 2, 让子进程执行 run 中的方法。 21 '''
1 from multiprocessing import Process 2 import os 3 class MyProcess(Process): 4 def __init__(self,*args,**kwargs): 5 self.args = args 6 super().__init__() 7 def run(self): 8 print(str(self.args[0]),"我是子进程,我的id是:", os.getpid(), "我的父亲的id 是 ", os.getppid()) 9 10 11 if __name__ == "__main__": 12 #开启 10个子进程 13 process_lists =[] 14 for i in range(10): 15 process = MyProcess(i) 16 process.start() 17 process_lists.append(process) 18 19 for process in process_lists: #一起批量 告诉 主线程! 20 process.join() 21 22 print("我是主进程,我的id 是", os.getpid()) 23 ''' 24 MyProcess().start() 中的.start() 做了两件事: 25 1, 开启子进程。 26 2, 让子进程执行 run 中的方法。 27 '''
1 # 第一种 方式(函数的方式)开启多进程 2 ''' 3 4 5 6 7 from multiprocessing import Process 8 import os 9 10 def test(*args,**kwargs): 11 print(str(args[0]), "我是子进程,我的pid 是: ",os.getpid()," 我父亲的pid 是 ",os.getppid()) 12 13 if __name__ == '__main__': 14 process_lists =[] 15 for i in range(10): 16 process = Process(target=test,args=(i,)) 17 process_lists.append(process) 18 process.start() 19 20 for process in process_lists: 21 process.join() 22 23 print("我是主进程,我的id 是 ",os.getpid()) 24 25 26 ''' 27 28 29 # 第二种 方式(面向对象的方式 )开启多进程 30 ''' 31 from multiprocessing import Process 32 import os 33 class MyProcess(Process): 34 def __init__(self,*args,**kwargs): 35 super().__init__() 36 self.args= args 37 def run(self): 38 print(str(self.args[0]),"我是子进程,我的pid 是:",os.getpid()," 我父亲的pid 是: ",os.getppid()) 39 40 if __name__ == '__main__': 41 process_lists = [] 42 for i in range(10): 43 process = MyProcess(i) 44 process_lists.append(process) 45 process.start() 46 47 for process in process_lists: 48 process.join() 49 print("我是主线程,我的pid 是:",os.getpid()) 50 '''
守护进程:
1 # 守护进程 2 ''' 3 4 from multiprocessing import Process 5 def test(): 6 print("我是子进程") 7 if __name__ == '__main__': 8 p = Process(target=test) 9 10 p.daemon =True # 这就将 p 设置成了 一个守护进程。 此时父进程牛逼。(注:设置必须在.start()前 ) 11 p.start() 12 print("我是主进程") 13 ''' 14 ''' 15 from multiprocessing import Process 16 class MyProcess(Process): 17 def run(self): 18 print("我是子进程") 19 20 if __name__ == '__main__': 21 process = MyProcess() 22 process.daemon = True # 此时,父进程就牛逼了 23 process.start() 24 print("我是主进程") 25 ''' 26 27 28 ''' 29 守护进程,会随着主进程代码执行完毕而结束! 30 ''' 31 from multiprocessing import Process 32 import time 33 def test01(): 34 time.sleep(5) 35 print("我是一个正常的子进程") 36 37 def test02(): 38 while True: 39 time.sleep(1) 40 print("我是一个守护进程,我要听父亲的") 41 42 if __name__ == '__main__': 43 44 process = Process(target=test01) 45 process.start() 46 47 process02 = Process(target=test02) 48 process02.daemon = True #我要听 父亲的,父亲的代码 执行完,我就死! 49 process02.start() 50 51 print("我是主进程 。。")
对于多进程之间 可能出现的同时操作同一个资源的时候,锁的运用:
1 from multiprocessing import Process,Lock 2 import json 3 import time 4 5 def addOneToFile(*args,**kwargs): 6 args[0].acquire() 7 with open("data.json","r",encoding="utf8") as f: 8 data_dict = json.load(f) 9 with open("data.json","w",encoding="utf8") as f: 10 data_dict["count"] += 1 11 json.dump(data_dict,f) 12 args[0].release() 13 14 15 if __name__ == '__main__': 16 with open("data.json","r",encoding="utf8") as f: 17 data_dict = json.load(f) 18 print("进程操作之前",data_dict["count"]) 19 20 process_lists = [] 21 lock = Lock() 22 for i in range(10): 23 process = Process(target=addOneToFile,args=(lock,)) 24 process_lists.append(process) 25 process.start() 26 for process in process_lists: #在此阻塞 主进程 27 process.join() 28 29 with open("data.json","r",encoding="utf8") as f: 30 data_dict = json.load(f) 31 print("进程操作之后",data_dict["count"])
1 from multiprocessing import Process,Lock 2 import json 3 4 def addOneToFile(): 5 with open("data.json","r",encoding="utf8") as f: 6 data_dict = json.load(f) 7 with open("data.json","w",encoding="utf8") as f: 8 data_dict["count"] += 1 9 json.dump(data_dict,f) 10 def getNumFromFile(): 11 with open("data.json","r",encoding="utf8") as f: 12 data_dict = json.load(f) 13 return data_dict["count"] 14 15 def main(*args,**kwargs): 16 17 print(str(args[0]),"我在查看数字,",getNumFromFile()) # 所有子进程可以同时 查看文件。但是不能同时 操作文件。 18 args[1].acquire() #args[1]是锁 19 addOneToFile() 20 args[1].release() #args[1]是锁 21 22 23 if __name__ == '__main__': 24 with open("data.json","r",encoding="utf8") as f: 25 data_dict = json.load(f) 26 print("进程操作之前",data_dict["count"]) 27 28 process_lists = [] 29 lock = Lock() 30 for i in range(10): #开10 个子进程 31 process = Process(target=main,args=(i,lock,)) 32 process_lists.append(process) 33 process.start() 34 35 for process in process_lists: 36 process.join() 37 38 with open("data.json","r",encoding="utf8") as f: 39 data_dict = json.load(f) 40 print("进程操作之后",data_dict["count"])
这里说的是个互斥锁 ,Lock 也就是 互斥锁。 锁上之后,必须打开,不可以连续锁两次。
信号量 semaphore:
它就是多个锁 。
1 from multiprocessing import Process,Semaphore 2 import random,time 3 4 ''' 5 6 #假设ktv 只有 4个房间, 7 def ktv(*args,**kwargs): 8 print(str(args[0])," 走进了ktv ") 9 time.sleep(random.randint(1,3)) 10 11 print(str(args[0]),"走出ktv") 12 if __name__ == '__main__': 13 for i in range(10): 14 Process(target=ktv,args=(i,)).start() 15 16 ''' 17 18 #下面是用信号量 19 #假设ktv 只有 4个房间, 20 def ktv(*args,**kwargs): 21 args[1].acquire() 22 print(str(args[0])," 走进了ktv ") 23 time.sleep(random.randint(1,3)) 24 args[1].release() 25 26 27 print(str(args[0]),"走出ktv") 28 if __name__ == '__main__': 29 # 信号量就是多个锁 30 locks = Semaphore(4) 31 for i in range(10): 32 Process(target=ktv,args=(i,locks)).start()
它的底层是 计数器 加 锁 来实现的。
事件 Event :
阻塞 事件 wait() 方法!
通过 set 设置 wait 为 False
通过 clear 设置 wait为 True
1 from multiprocessing import Process,Event 2 import time 3 4 def traffic_light(*args,**kwargs): 5 while True: 6 if args[0].is_set(): 7 args[0].clear() 8 print("红灯亮起...2s",time.time()) 9 time.sleep(2) 10 else: 11 args[0].set() 12 print("绿灯亮起...5s",time.time()) 13 time.sleep(5) 14 15 16 def car(*args,**kwargs): 17 for i in range(20): 18 args[0].wait() # 默认是 True 19 print("第{}个车通过了...".format(i),time.time()) 20 time.sleep(1) #每个车通过要 1s 21 22 if __name__ == "__main__": 23 event = Event() 24 process_light = Process(target=traffic_light,args=(event,)) 25 process_light.start() 26 27 process_car = Process(target=car,args=(event,)) 28 process_car.start() 29 30 ''' 31 绿灯亮起...5s 1576229043.0750947 32 第0个车通过了... 1576229043.090026 33 第1个车通过了... 1576229044.09144 34 第2个车通过了... 1576229045.0923135 35 第3个车通过了... 1576229046.0925462 36 第4个车通过了... 1576229047.1016579 37 红灯亮起...2s 1576229048.075822 38 绿灯亮起...5s 1576229050.076733 39 第5个车通过了... 1576229050.076733 40 第6个车通过了... 1576229051.07784 41 第7个车通过了... 1576229052.0801845 42 第8个车通过了... 1576229053.080349 43 第9个车通过了... 1576229054.0866182 44 红灯亮起...2s 1576229055.0775924 45 绿灯亮起...5s 1576229057.0793915 46 第10个车通过了... 1576229057.0793915 47 第11个车通过了... 1576229058.08144 48 第12个车通过了... 1576229059.0825326 49 第13个车通过了... 1576229060.083491 50 第14个车通过了... 1576229061.1057897 51 红灯亮起...2s 1576229062.0795844 52 绿灯亮起...5s 1576229064.0796192 53 第15个车通过了... 1576229064.0796192 54 第16个车通过了... 1576229065.0797496 55 第17个车通过了... 1576229066.080157 56 第18个车通过了... 1576229067.0806174 57 第19个车通过了... 1576229068.0913792 58 59 '''
1 import time 2 from multiprocessing import Process,Event 3 4 def traffic_light(*args): 5 while True: 6 if args[0].is_set(): # is_set() :wait 是否被 set了 False (默认wait 是 True ) 7 args[0].clear() #设置 下面的 wait 为 True 8 print("红灯亮,时间为4s",time.time()) 9 time.sleep(4) 10 else: 11 args[0].set() # set 下面的wait 为 False 12 print("绿灯亮,时间为10s",time.time()) 13 time.sleep(10) 14 15 def car(*args): 16 for i in range(20): 17 args[0].wait() # wait 一开始就是True , 外面代码可以通过set 设置为False ,可以通过clear 设置为True 18 time.sleep(2) #每次通过要 2s 19 print("第{}车 通过了 路口...".format(i),time.time()) 20 if __name__ == '__main__': 21 event = Event() 22 process_light = Process(target=traffic_light,args=(event,)) 23 process_light.start() 24 25 process_car = Process(target=car,args=(event,)) 26 process_car.start() 27 28 ''' 29 绿灯亮,时间为10s 1576228303.6506903 30 第0车 通过了 路口... 1576228305.6631992 31 第1车 通过了 路口... 1576228307.67837 32 第2车 通过了 路口... 1576228309.695913 33 第3车 通过了 路口... 1576228311.704143 34 红灯亮,时间为4s 1576228313.6609156 35 第4车 通过了 路口... 1576228313.7077675 36 绿灯亮,时间为10s 1576228317.668394 37 第5车 通过了 路口... 1576228319.6812973 38 第6车 通过了 路口... 1576228321.6966455 39 第7车 通过了 路口... 1576228323.6967888 40 第8车 通过了 路口... 1576228325.697942 41 红灯亮,时间为4s 1576228327.684015 42 第9车 通过了 路口... 1576228327.703794 43 绿灯亮,时间为10s 1576228331.7040083 44 第10车 通过了 路口... 1576228333.7137098 45 第11车 通过了 路口... 1576228335.713929 46 第12车 通过了 路口... 1576228337.7339544 47 第13车 通过了 路口... 1576228339.7438996 48 红灯亮,时间为4s 1576228341.7042365 49 第14车 通过了 路口... 1576228341.7442398 50 绿灯亮,时间为10s 1576228345.7137616 51 第15车 通过了 路口... 1576228347.7242248 52 第16车 通过了 路口... 1576228349.7437382 53 第17车 通过了 路口... 1576228351.7443385 54 第18车 通过了 路口... 1576228353.7589884 55 红灯亮,时间为4s 1576228355.7238946 56 第19车 通过了 路口... 1576228355.7639687 57 绿灯亮,时间为10s 1576228359.7241712 58 红灯亮,时间为4s 1576228369.7442408 59 绿灯亮,时间为10s 1576228373.7638867 60 61 '''
进程间通信:
进程间 通信:简称IPC (Inter Process Communciation ):
那么现在我们想让 进程间通信,怎么办?
这里主要是:进程 队列 (一般队列, JoinableQueue)和 管道。
生产者 与消费者模型:
它适用于 两个处理速度差别很大的情况!
1 from multiprocessing import Process,Queue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 if food is None:break 8 print("吃了一个{}...".format(food)) 9 time.sleep(random.uniform(0.3,0.8)) 10 def producer(*args): 11 for i in range(10): 12 args[0].put(args[1]) 13 print("生产了一个{}".format(args[1])) 14 time.sleep(random.uniform(0.5,1)) 15 16 if __name__ == '__main__': 17 q = Queue() 18 process_c1 = Process(target=consumer,args=(q,)) 19 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 20 process_p1.start() 21 process_c1.start() 22 23 process_p1.join() 24 25 q.put(None)
1 from multiprocessing import Process,Queue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 if food is None:break 8 print("吃了一个{}...".format(food)) 9 time.sleep(random.uniform(0.3,0.8)) 10 def producer(*args): 11 for i in range(10): 12 args[0].put(args[1]) 13 print("生产了一个{}".format(args[1])) 14 time.sleep(random.uniform(0.5,1)) 15 16 if __name__ == '__main__': 17 q = Queue() 18 process_c1 = Process(target=consumer,args=(q,)) 19 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 20 process_p2 = Process(target=producer,args=(q,"油条",)) # 生产者2 生产10个 包子 ! 21 22 process_p1.start() 23 process_p2.start() 24 process_c1.start() 25 26 process_p1.join() 27 process_p2.join() 28 29 q.put(None)
1 from multiprocessing import Process,Queue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 if food is None:break 8 print("吃了一个{}...".format(food)) 9 time.sleep(random.uniform(0.3,0.8)) 10 def producer(*args): 11 for i in range(10): 12 args[0].put(args[1]) 13 print("生产了一个{}".format(args[1])) 14 time.sleep(random.uniform(0.5,1)) 15 16 if __name__ == '__main__': 17 q = Queue() 18 process_c1 = Process(target=consumer,args=(q,)) 19 process_c2 = Process(target=consumer,args=(q,)) 20 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 21 22 23 process_p1.start() 24 25 process_c1.start() 26 process_c2.start() 27 28 process_p1.join() 29 30 31 q.put(None) 32 q.put(None) #有几个消费者就要 有几个.put() 结束标志
1 from multiprocessing import Process,Queue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 if food is None:break 8 print("吃了一个{}...".format(food)) 9 time.sleep(random.uniform(0.3,0.8)) 10 def producer(*args): 11 for i in range(10): 12 args[0].put(args[1]) 13 print("生产了一个{}".format(args[1])) 14 time.sleep(random.uniform(0.5,1)) 15 16 if __name__ == '__main__': 17 q = Queue() 18 process_c1 = Process(target=consumer,args=(q,)) 19 process_c2 = Process(target=consumer,args=(q,)) 20 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 21 process_p2 = Process(target=producer,args=(q,"油条",)) 22 23 process_p1.start() 24 process_p2.start() 25 process_c1.start() 26 process_c2.start() 27 28 process_p1.join() 29 process_p2.join() 30 31 q.put(None) 32 q.put(None) #有几个消费者就要 有几个.put() 结束标志
JoinableQueue:
JoinableQueue类 ,相对于 Queue 类来说,多了两个方法 一个是 task_done() ,一个是join()
put 进去之后,计数器会自动加1 ,但是从里面 get() 是不会自动减一的,除非要 调用task_done()
task_done() 告诉队列计数减一。
q.join() 一直阻塞,直到队列中的所有 计数为0 时,结束。
1 from multiprocessing import Process,JoinableQueue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 if food is None:break 8 print("吃了一个{}...".format(food)) 9 time.sleep(random.uniform(0.3,0.8)) 10 def producer(*args): 11 for i in range(8): 12 args[0].put(args[1]) 13 print("生产了一个{}".format(args[1])) 14 time.sleep(random.uniform(0.5,1)) 15 16 if __name__ == '__main__': 17 q = JoinableQueue() 18 process_c1 = Process(target=consumer,args=(q,)) 19 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 20 21 process_p1.start() 22 process_c1.start() 23 24 process_p1.join() 25 26 q.put(None) #有几个消费者就要 有几个.put() 结束标志
这样是对的,但是我们不想在最后再,put(None)作为结束标志了。
1 from multiprocessing import Process,JoinableQueue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 print("吃了一个{}...".format(food)) 8 time.sleep(random.uniform(0.3,0.8)) 9 args[0].task_done() # 此时 队列计数器才会减一 ! 10 11 def producer(*args): 12 for i in range(8): 13 args[0].put(args[1]) # 放入队列的时候,会加一! 14 print("生产了一个{}".format(args[1])) 15 # time.sleep(random.uniform(0.5,1)) 16 17 if __name__ == '__main__': 18 q = JoinableQueue() 19 process_c1 = Process(target=consumer,args=(q,)) 20 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 21 process_c1.daemon = True # 将生产函数变为 守护进程!!!,当 主进程最后的代码执行完毕,它也会跟着结束。 22 23 process_p1.start() 24 process_c1.start() 25 26 process_p1.join() #阻塞主进程 ,直到p1 生产完毕! 27 q.join() # 放到哪 阻塞哪,直到 q变为空!!! #此时,主进程被阻塞在这, 直到q变为0
1 from multiprocessing import Process,JoinableQueue 2 import time,random 3 4 def consumer(*args): 5 while True: 6 food = args[0].get() 7 print("吃了一个{}...".format(food)) 8 time.sleep(random.uniform(0.3,0.8)) 9 args[0].task_done() # 此时 队列计数器才会减一 ! 10 11 def producer(*args): 12 for i in range(8): 13 args[0].put(args[1]) # 放入队列的时候,会加一! 14 print("生产了一个{}".format(args[1])) 15 time.sleep(random.uniform(0.2,0.4)) 16 17 if __name__ == '__main__': 18 q = JoinableQueue() 19 process_c1 = Process(target=consumer,args=(q,)) 20 process_c2 = Process(target=consumer,args=(q,)) 21 process_p1 = Process(target=producer,args=(q,"包子",)) # 生产者1 生产10个 包子 ! 22 process_p2 = Process(target=producer,args=(q,"油条",)) # 生产者1 生产10个 油条 ! 23 process_c1.daemon = True # 将生产函数变为 守护进程!!!,当 主进程最后的代码执行完毕,它也会跟着结束。 24 process_c2.daemon = True # 将生产函数变为 守护进程!!!,当 主进程最后的代码执行完毕,它也会跟着结束。 25 26 process_p1.start() 27 process_p2.start() 28 process_c1.start() 29 process_c2.start() 30 31 process_p1.join() #阻塞主进程 ,直到p1 生产完毕! 32 q.join() # 放到哪 阻塞哪,直到 q变为空!!! #此时,主进程被阻塞在这, 直到q变为0
此时,就解决了 consumer () 函数的结束问题。 我们就不需要再 最后看有几个消费者 就put() 几个None 了。
管道:
进程间的通信 使用队列就行了!
进程池:
多进程的目的 就是为了充分占用 CPU ,如果对于计算密集型的,可以。
如果对于IO密集型的,就不适合 开启多进程了。
为什么要有 进程池:
这里面 500衣服是任务, 500人是进程,4台机器是 cpu 。
进程池中总共开了4个进程 和 分别 开启四个进程 :
1 from multiprocessing import Pool 2 import time 3 4 def test(*args): 5 print("正在执行 {}".format(args[0])) 6 7 if __name__ == '__main__': 8 start_time = time.time() 9 pool = Pool(4) #进程池 有四个进程 10 for i in range(100): 11 pool.apply_async(test,args=(i,)) 12 13 #关闭进程池 14 pool.close() 15 pool.join()# 阻塞 主进程 16 print("总共耗时: {}".format(time.time() - start_time)) #总共耗时: 1.171598196029663
1 from multiprocessing import Process 2 import time 3 4 def test(*args): 5 print("正在执行 {}".format(args[0])) 6 7 if __name__ == '__main__': 8 start_time = time.time() 9 process_lists = [] 10 for i in range(100): 11 process = Process(target=test,args=(i,)) 12 process_lists.append(process) 13 process.start() 14 15 for process in process_lists: process.join() 16 print("总共耗时: {}".format(time.time() - start_time)) #总共耗时: 21.31679654121399
所以,我们不是依据,任务书来开进程的,这样会很卡,我们应该开个进程池,让所有任务在池子里工作。
总结:
多进程,开多任务的时候,超过5个任务的都要搞成一个池!
补充:
1 from multiprocessing import Pool 2 import os 3 4 5 def test(*args): 6 print(str(args[0]),"我是子进程 我的pid是",os.getpid()) 7 8 if __name__ == '__main__': 9 pool = Pool(os.cpu_count()+1) #对于高计算型的,多开一个进程可以提高cpu的时间占有 : 10 #1,假设系统 总共有16 个进程,我们再开4个:此时我们程序的cpu占有率:4/20 = 20% 11 #2,假设系统 总共有16 个进程,我们再开5个:此时我们程序的cpu占有率:5/21 = 24% 12 #所以可以考虑,多开一个,这样会提高我们对cpu 的占有率。 13 for i in range(20): #20个任务 14 pool.apply_async(test,args=(i,)) 15 16 # 关闭pool 17 pool.close() 18 # 阻塞主进程 19 pool.join()
使用进程池爬取 多个url :
1 from multiprocessing import Pool 2 import requests 3 import re 4 import time 5 6 # 子进程 访问网页,主进程 处理网页的结果! 7 url_lists = [ 8 "http://www.baidu.com", 9 "http://www.sohu.com", 10 "http://www.sina.com", 11 "http://www.cnblogs.com", 12 "http://www.7k7k.com" 13 ] 14 15 16 def get_data(url): 17 response = requests.get(url) 18 return response.content,re.findall(".([a-zA-Z0-9]+).",url)[0] 19 20 def call_bk(data): 21 with open(data[1] + ".html","wb") as f: 22 f.write(data[0]) 23 24 if __name__ == '__main__': 25 start_time = time.time() 26 pool = Pool(4) 27 for url in url_lists: 28 pool.apply_async(get_data,args=(url,),callback=call_bk ) 29 30 pool.close() 31 pool.join() 32 print("总共耗时: ",time.time()- start_time) #总共耗时: 1.9826991558074951
里面的call_bk() 的作用是,当子进程执行完之后 ,把返回结果返回给回调函数,并在主进程中执行 回调函数!!!!
线程:
进程是计算机中最小的资源分配 单位,
而下面的线程是 计算机中 cpu 可以调度(执行)的最小单位。
1 from threading import Thread 2 import time,os 3 def test(*args): 4 time.sleep(1) 5 print(str(args[0]),"我是子线程 ,我这里的进程 pid 是 ",os.getpid()) 6 7 8 if __name__ == '__main__': #注:这里也可以 不用这个 结构,因为我们在这里开的是 多线程!!! 9 print("我是主进程 我的pid,",os.getpid()) 10 for i in range(10): 11 t = Thread(target=test,args=(i,)) 12 t.start()
下面看 我们开 10 个线程 和 10 个线程之间的对比:
首先看 10个进程:
1 from multiprocessing import Process 2 import time,os 3 def test(*args): 4 time.sleep(1) 5 print(str(args[0]),"我在执行....") 6 7 if __name__ == '__main__': #注:这里也可以 不用这个 结构,因为我们在这里开的是 多线程!!! 8 t1 = time.time() 9 process_lists = [] 10 for i in range(10): 11 process = Process(target=test,args=(i,)) 12 process_lists.append(process) 13 process.start() 14 15 #阻塞 主线程 16 for process in process_lists: 17 process.join() 18 print("总共耗时为: ",time.time() - t1) #总共耗时为: 3.408578634262085
开4个进程,使用进程池:
1 from multiprocessing import Pool 2 import time,os 3 def test(*args): 4 time.sleep(1) 5 print(str(args[0]),"我在执行....") 6 7 if __name__ == '__main__': #注:这里也可以 不用这个 结构,因为我们在这里开的是 多线程!!! 8 t1 = time.time() 9 pool = Pool(4) 10 for i in range(10): 11 pool.apply_async(test,args=(i,)) 12 pool.close() 13 pool.join() #阻塞 主进程 14 15 print("总共耗时为: ",time.time() - t1) #总共耗时为: 3.9842326641082764
下面是重头戏,看开10个线程:
10个 线程:
1 from threading import Thread 2 import time,os 3 def test(*args): 4 time.sleep(1) 5 print(str(args[0]),"我在执行....") 6 7 if __name__ == '__main__': #注:这里也可以 不用这个 结构,因为我们在这里开的是 多线程!!! 8 t1 = time.time() 9 thread_lists = [] 10 for i in range(10): 11 thread = Thread(target=test,args=(i,)) 12 thread_lists.append(thread) 13 thread.start() 14 15 #阻塞 主线程 16 for thread in thread_lists: 17 thread.join() 18 print("总共耗时为: ",time.time() - t1) #耗时: 1.0042662620544434
从中,我们可明显的感觉到 线程的轻量级!!!
线程间是数据共享的:
1 from threading import Thread 2 3 num = 100 4 def test(*args): 5 global num 6 num -= 1 7 8 if __name__ == '__main__': 9 thread_lists = [] 10 for i in range(100): 11 thread = Thread(target=test,args=(i,)) 12 thread_lists.append(thread) 13 thread.start() 14 15 for thread in thread_lists: 16 thread.join() #阻塞 主线程 。。。。 17 print("num :",num)
1 from threading import Thread 2 import time 3 4 def test(): 5 time.sleep(3) 6 7 if __name__ == '__main__': 8 thread = Thread(target=test) 9 thread.start() 10 print(thread.isAlive()) 11 print(thread.is_alive()) 12 print(thread.getName()) 13 thread.setName("T1") 14 print(thread.getName())
1 from threading import Thread,currentThread 2 import time,os 3 4 def test(): 5 print("子线程的 线程id ",currentThread().ident) 6 print("子线程的 进程id ",os.getpid()) 7 time.sleep(3) 8 9 if __name__ == '__main__': 10 print("主线程的 线程id ",currentThread().ident) 11 print("主进程的 进程id ",os.getpid()) 12 13 thread = Thread(target=test) 14 thread.start()
守护线程:
守护线程的设置 基本和 守护进程一致,但是效果却是不一样的。
1 from threading import Thread 2 import time 3 4 def test01(): 5 while True: 6 time.sleep(1) 7 print("我是守护子线程~") 8 9 def test02(): 10 time.sleep(3) 11 print("我是子线程....") 12 13 if __name__ == '__main__': 14 thread = Thread(target=test01) 15 thread.daemon = True 16 thread.start() 17 18 thread2 = Thread(target=test02) 19 thread2.start() 20 print("主线程的代码结束!") # 这里的守护线程 和 守护进程 就不一样了,进程守护的是 主进程。 线程守护的是 其他子线程。
在进程中,守护进程守护的是主进程。守护进程是 在主进程的代码执行完之后,结束。
在线程中 ,守护线程守护的是其他线程。守护线程是在其他所有子线程执行完之后,结束。
证明如下:
1 from threading import Thread 2 import time 3 4 def test01(): 5 while True: 6 time.sleep(1) 7 print("我是守护子线程~") 8 9 def test02(): 10 time.sleep(3) 11 print("我是子线程 test02") 12 13 14 def test03(): 15 time.sleep(5) 16 print("我是子线程 test03") 17 18 if __name__ == '__main__': 19 thread = Thread(target=test01) 20 thread.daemon = True 21 thread.start() 22 23 thread2 = Thread(target=test02) 24 thread2.start() 25 26 thread3 = Thread(target=test03) 27 thread3.start() 28 29 print("主线程的代码结束!") # 这里的守护线程 和 守护进程 就不一样了,进程守护的是 主进程。 线程守护的是 其他子线程。
GIL 全局解释器锁 :
锁的是 线程 而不是数据。