• 进程_线程_协程回顾!


    进程

    进程的 两关系一特点

        '''
            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 全局解释器锁 : 

    锁的是 线程 而不是数据。 

  • 相关阅读:
    Android 懒加载简单介绍
    Android 使用RxJava实现一个发布/订阅事件总线
    Android 第三方库RxLifecycle使用
    Android 使用Retrofit2.0+OkHttp3.0实现缓存处理+Cookie持久化第三方库
    代码雨
    我的第一个博客(My first blog)
    merge法
    如何使用git将remote master上的内容merge 到自己的开发分支上  &  以及将自己分支的内容merge到remote master上...
    git 解决冲突
    Mac安装和破解激活Charles
  • 原文地址:https://www.cnblogs.com/zach0812/p/12036271.html
Copyright © 2020-2023  润新知