进程_线程_协程回顾!

进程

进程的 两关系一特点

    '''
        1,关系 :
            a, 父进程 和 子进程:  父进程只是通知操作系统开启,子进程,然后继续执行自己的进程!(异步)
            b, 子进程 和 子进程:  子进程 与 子进程之间 是数据隔离的。

        2,特点:
            父进程 执行完自己的代码后,会等所有子进程执行完之后,才会结束父进程。    
    '''
    '''
        1,关系:
            a,
            b,衍生的问题:进程间如何通信 ,我们可以通过 进程队列(Queue)解决。
        
        2,特点:
            如何使得 当所有子进程的代码都执行完之后,再执行父进程,也就是阻塞父进程。 
    '''

子进程.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     
View Code

第二种,使用面向对象方式 开启子进程:

 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     '''
view code

使用面向对象方式,如何给子进程  传递参数:

 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     '''
开启多个子进程,并使用join方法!
 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("我是主进程 。。")
View Code

对于多进程之间 可能出现的同时操作同一个资源的时候,锁的运用:

 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"])
View Code
 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"])
加锁的案例. json 文件中的内容是:{“count”:10}

这里说的是个互斥锁 ,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()
View Code

它的底层是 计数器 加 锁 来实现的。 

事件 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 '''
View Code
 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 '''
View Code

进程间通信:

进程间 通信:简称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
使用JoinableQueue 一个生产者,一个消费者
 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
使用进程池(开四个进程),处理100个任务
 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
开了 100个进程,大大的卡!

所以,我们不是依据,任务书来开进程的,这样会很卡,我们应该开个进程池,让所有任务在池子里工作。 

总结: 

多进程,开多任务的时候,超过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()
View Code

使用进程池爬取 多个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
使用进程池:爬取多个URL 总共耗时: 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
View Code

开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
View Code

下面是重头戏,看开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
View Code

从中,我们可明显的感觉到 线程的轻量级!!!  

线程间是数据共享的:

 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()
使用threading 中的 currentThread() 来查看线程id ~

守护线程:

守护线程的设置 基本和 守护进程一致,但是效果却是不一样的。

 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("主线程的代码结束!") # 这里的守护线程 和  守护进程 就不一样了,进程守护的是 主进程。  线程守护的是 其他子线程。
View Code

GIL 全局解释器锁 : 

锁的是 线程 而不是数据。 

原文地址:https://www.cnblogs.com/zach0812/p/12036271.html