2017/11/4 进程间通信,进程池 

 进程间通信(IPC,inter-process communication):生产进程生产食物,消费进程购买食物,消费进程一直监视生产状况,只要一有食物就将其取出来,如果取到食物None,两者关系结束,于是主进程也结束。 

 远程过程调用协议(remote procedure call protocal),需要某些传输协议 

 一般情况下 父进程会等子进程结束再结束 



 ===================================================================== 

 1.进程间通信常用方式: 

 进程间传递数据 

 (1)队列: 

 from multiprocessing import Queue(multiprocessing.Queue) 

 (前一章:from queue import PriorityQueue 



 A.from multiprocessing import Queue(multiprocessing.Queue): 

 在多线程中传递数据,交换数据,进行通信; 

 它与一般的数据结构中的队列的差别为更加符合多进程的特性:序列化和反序列化; 

 对数据做了一些通信商的加工,保证多进程的安全性; 

 在这里使用多进程的数据通信,不需要考虑多进程可能带来的安全隐患,直接使用; 

 multiprocessing.Queue在进程间通信是python比价提倡的一种方式 



 B.from queue import PriorityQueue(queue.PriorityQueue): 

 存储数据的一种数据结构 



 (2)管道: 

 管道中,子进程间只能单向通信,一个子进程在定义管道后只能get或者put; 

 conn1只能接消息,conn2只能发送消息,不用的一端close(原因在于单缓存),如果要实现双向通信,就设置两根管道 

 但是队列中子进程既可以get也可以put; 

 匿名管道:只能在父子进程中使用 

 命名管道:没有沁园关系的进程之间也可以通信 



 (3)文件: 

 open,read,write,seek,tell,close 

 mode:r,w,a,b 

 with open('test.txt') as f:  #该操作方式可以自行关闭文件 不必f.close() 

 早期时各种硬件设备都是私有接口,unix系统将设备文件化,用r,w,a,b等api接口对设备进行操作 

 (4)共享内存 

 ------------------------------- 

 进程间传递信号 

 (5)信号量 

 (6)事件 

 (7)互斥量 

 from multiprocessing import Lock 

 lock.acquire()  

 money.value += 1      #注意锁的粒度,尽快最小话,开销最小;粒度最小原则 

 lock.release() 

 -------------------------------- 

 (8)Socket 





 ===================================================================== 

 作业: 

 (1)队列实现生产者消费者模型;生产者生产[0,1,2,3,4,5,6,7,8,9,10] 

 消费者能够在处理完list序列后退出 

 (2)使用互斥锁去完成银行存取款操作,存款10000,A取10次,每次取100;B存5次,每次存200 

 (3)面向对象方法实现第一个作业的第二题myTimer 



 (1) 

 from multiprocessing import Queue 

 from multiprocessing import Process 

 import time 



 def consumer(input_q):  

      while True: 

          item = input_q.get() 

          if item == None:                

              break 

          print(item) 



 def producer(sequence,output_p): 

      for i in sequence: 

          time.sleep(1) 

          output_p.put(i) 



 if __name__ == '__main__': 

      q= Queue() 

      con_p = Process(target=consumer,args=(q,))   

      con_p.start() 

      sequence =[1,2,3,4,5,6,7,8,9,10] 

      producer(sequence,q)   

      q.put(None)  



 (2) 

 from multiprocessing import Process 

 from multiprocessing import Value   #在不同的进程间共享的变量 

 from multiprocessing import Lock 

 import time 



 def deposit(money,lock):    #存钱 

     for i in range(5): 

         time.sleep(0.001) 

         lock.acquire()   #上锁的操作 

         money.value += 200 

         lock.release() 



 def withdraw(money,lock):   #取钱 

     for i in range(10): 

         time.sleep(0.001) 

         lock.acquire()    

         money.value -= 100 

         lock.release() 



 if __name__ == '__main__': 

     money = Value('i',2000)  

     lock = Lock()  



     d = Process(target=deposit,args=(money,lock)) 

     d.start() 

     w = Process(target=withdraw,args=(money,lock)) 

     w.start() 

     d.join() 

     w.join() 



     print(money.value)   



 (3) 

 from multiprocessing import Process 

 import time 

 import os 



 class Proces: 

     def __init__(set,interval): 

         self.interval = interval 



     def new_start(self): 

         p = Process(target = self.run,args =()) 

         p.start() 



         print('child process id is %d,name is %s' % (p.pid,p.name)) 

          

         print(os.getpriority(os.PRIO_PROCESS,p.pid)) 

         os.setpriority(os.PRIO_PROCESS,p.pid,1)        #获取进程改优先级 

         print(os.getpriority(os.PRIO_PROCESS,p.pid)) 



         p.join() 

         print('main process') 



 class Timer(Proces): 

     def __init__(self,interval): 

         self.interval = interval 



     def run(self):  #打印时间的方法 

         for i in range(5): 

             time.sleep(self.interval) 

             print(time.ctime()+'have a rest') 

              

 if __name__ == '__main__': 

     t = Timer(2) #创建定时器 
    t.new_start()   #继承process  do not call run   父类中函数会自动调用这个run方法

================================================================================================
相关代码:
设置优先级1-20,做一个模拟os的调度程序:某一时刻,四个进程:
 Watch TV:          random优先级  import rnadom
 Listen to music:   random优先级
 Print Doc:         4
 Write Doc:         4
 创建队列,信息放进队列,模拟队列的调度(观察取数情况,验证时间片)


 我的解法:
 from queue import PriorityQueue 
 # import random
 # class Item(object):


 #     def __init__(self,name,level):      #self 可以将属性写进去
 #         self.name = name
 #         self.level = level


 #     def __repr__(self):
 #         return (str(self.name) + ':' + str(self.level))


 #     def __lt__(self,other):      #小于的比较 重写
 #         return self.level > other.level


 # if __name__ == '__main__':
 #     q = PriorityQueue()
 #     q.put(Item('watch tv',random.randint(1,20)))
 #     q.put(Item('music',random.randint(1,20)))
 #     q.put(Item('print',4))
 #     q.put(Item('write',4))


 #     while not q.empty():
 #         print(q.get())


 #===============================================================================================
 多进程定期器:每一个小时,你的定时器提示你:不要coding,休息一下吧!
 提示的同时显示当前进程的pid,name,os模块设置优先级


 我的解法:


 # from multiprocessing import Process
 # import time


 # def getTime(interval):
 #     while True:
 #         time.sleep(interval)
 #         print(time.ctime())


 # if __name__ == '__main__':
 #     p = Process(target=getTime,args=(1,))
 #     p.start()
 #     print(p.name,p.pid)   #子进程 子进程的id


 #     p.join()   #等待子进程结束 实际是阻塞
 #     print('ending')    #由于子进程无线循环,由于join(),导致主进程无法运行,等待子进程结束,形成阻塞


 #===============================================================================================


 #显示进程id,优先级
 # from multiprocessing import Process
 # import time
 # import os


 # def getTime(interval):
 #     while True:
 #         time.sleep(interval)
 #         print(time.ctime())


 # if __name__ == '__main__':
 #     p = Process(target=getTime,args=(1,))
 #     p.start()
 #     print('子进程的名字和id:',p.name,p.pid)   #子进程 子进程的id
     
 #     print(os.getpriority(os.PRIO_PROCESS,p.pid))
 #     os.setpriority(os.PRIO_PROCESS,p.pid,1)        #获取进程改优先级
 #     print(os.getpriority(os.PRIO_PROCESS,p.pid))


 #     p.join()   #等待子进程结束 实际是阻塞
 #     print('ending')    #由于子进程无线循环,由于join(),导致主进程无法运行,等待子进程结束,形成阻塞


 #===============================================================================================


 #将定时器改成面向对象的形式@@@@@@@@@@@@@已经完成,在20171106代码文件中
 # from multiprocessing import Process
 # import time
 # import os


 # class Timer(Process):
 #     def __init__(self,interval):
 #         self.sleep = interval


 #     def run(self):  #打印时间的方法
             time.sleep(interval)
             print(time.ctime()+'have a rest')
             print(os.getpriority(os.PRIO_PROCESS,p.pid))
             os.setpriority(os.PRIO_PROCESS,p.pid,1)        #获取进程改优先级
             print(os.getpriority(os.PRIO_PROCESS,p.pid))


 #     if __name__ == '__main__':
 #         t = Timer(3600) #创建定时器
 #         t.start()   #继承process  do not call run   父类中函数会自动调用这个run方法


 #===============================================================================================
 #===============================================================================================


 20171104作业 - 老师的解法


 设置优先级1-20,做一个模拟os的调度程序:某一时刻,四个进程:
 Watch TV:          random优先级  import rnadom
 Listen to music:   random优先级
 Print Doc:         4
 Write Doc:         4
 创建队列,信息放进队列,模拟队列的调度(观察取数情况,验证时间片)




 # from queue import PriorityQueue 
 # import random
 # class Item(object):


 #     def __init__(self,name,level):      #self 可以将属性写进去
 #         self.name = name
 #         self.level = level


 #     def __repr__(self):
 #         return (str(self.name) + ':' + str(self.level))


 #     def __lt__(self,other):      #小于的比较 重写
 #         return self.level > other.level


 # if __name__ == '__main__':
 #     q = PriorityQueue()
 #     q.put(Item('watch tv',random.randint(1,20)))
 #     q.put(Item('music',random.randint(1,20)))
 #     q.put(Item('print',4))
 #     q.put(Item('write',4))


 #     while not q.empty():
 #         print(q.get())


 #     q.put(Item('print',4+q.qsize()))
 #     q.put(Item('write',4+q.qsize()))


 #===============================================================================================


 20171104作业- 老师的解法


 多进程定期器:每一个小时,你的定时器提示你:不要coding,休息一下吧!
 提示的同时显示当前进程的pid,name,os模块设置优先级


 # from multiprocessing import Process
 # import time


 # def getTime(interval):
 #     while True:
 #         time.sleep(interval)
 #         print(time.ctime())


 # if __name__ == '__main__':
 #     p = Process(target=getTime,args=(1,))
 #     p.start()
 #     print(p.name,p.pid)   #子进程 子进程的id


 #     p.join()   #等待子进程结束 实际是阻塞
 #     print('ending')    #由于子进程无线循环,由于join(),导致主进程无法运行,等待子进程结束,形成阻塞


 #==================================


 #显示进程id,优先级
 # from multiprocessing import Process
 # import time
 # import os


 # def getTime(interval):
 #     while True:
 #         time.sleep(interval)
 #         print(time.ctime())


 # if __name__ == '__main__':
 #     p = Process(target=getTime,args=(1,))
 #     p.start()
 #     print('子进程的名字和id:',p.name,p.pid)   #子进程 子进程的id
     
 #     print(os.getpriority(os.PRIO_PROCESS,p.pid))
 #     os.setpriority(os.PRIO_PROCESS,p.pid,1)        #获取进程改优先级
 #     print(os.getpriority(os.PRIO_PROCESS,p.pid))


 #     p.join()   #等待子进程结束 实际是阻塞
 #     print('ending')    #由于子进程无线循环,由于join(),导致主进程无法运行,等待子进程结束,形成阻塞


 #=================================


 #将定时器改成面向对象的形式
 # from multiprocessing import Process
 # import time
 # import os


 # class Timer(Process):
 #     def __init__(self,interval):
 #         self.sleep = interval


 #     def run(self):  #打印时间的方法
 #             time.sleep(interval)
             # print(time.ctime()+'have a rest')
             # print(os.getpriority(os.PRIO_PROCESS,p.pid))
             # os.setpriority(os.PRIO_PROCESS,p.pid,1)        #获取进程改优先级
             # print(os.getpriority(os.PRIO_PROCESS,p.pid))


 #     if __name__ == '__main__':
 #         t = Timer(3600) #创建定时器
 #         t.start()   #继承process  do not call run   父类中函数会自动调用这个run方法




 #===============================================================================================
 #===============================================================================================


 20171106课堂练习代码


 #生产消费模型


 # from multiprocessing import Queue
 # from multiprocessing import Process
 # import time


 # #消费者模型
 # def consumer(input_q):
 #     time.sleep(2)
 #     while not input_q.empty():
 #         print(input_q.get())


 # #生产者逻辑
 # def producer(sequence,output_p):
 #     for i in sequence:
 #         output_p.put(i)






 # if __name__ == '__main__':
 #     q= Queue()
 #     con_p = Process(target=consumer,args=(q,))
 #     con_p.start()


 #     sequence =[1,2,3,4,5]
 #     producer(sequence,q)


 #=================================


 #生产消费模型
 # from multiprocessing import Queue
 # from multiprocessing import Process
 # import time


 # #消费者模型
 # def consumer(input_q):
 #     time.sleep(2)
 #     while True:
 #         if not input_q.empty():
 #             print(input_q.get())
 #         else:
 #             break
 # #生产者逻辑
 # def producer(sequence,output_p):
 #     for i in sequence:
 #         output_p.put(i)






 # if __name__ == '__main__':
 #     q= Queue()
 #     con_p = Process(target=consumer,args=(q,))
 #     con_p.start()


 #     sequence =[1,2,3,4,5]
 #     producer(sequence,q)


 #=================================


 # #生产消费模型 
 # from multiprocessing import Queue
 # from multiprocessing import Process
 # import time


 # #消费者模型
 # def consumer(input_q):  #input_q  声明参数  从生产者那里拿走物品(数据,队列数据)
 #     while True:
 #         item = input_q.get()
 #         if item == None:       #用None作为标志,判断生产者是否已经结束了生产
         
 #             break
 #         print(item)


 # #生产者逻辑
 # def producer(sequence,output_p):


 #     for i in sequence:
 #         time.sleep(1)
 #         output_p.put(i)


 # if __name__ == '__main__':
 #     q= Queue()
 #     con_p = Process(target=consumer,args=(q,))  #消费者进程 创建一个进程,进程的目标一定是个函数名,或者值类中的函数名即方法名,进程的参数
 #     con_p.start()


 #     sequence =[1,2,3,4,5]
 #     # pro_p = Process(target=producer,args=(sequence,q))  #消费者进程
 #     # pro_p.start()
 #     producer(sequence,q)  #  生产者开始生产数字12345,放入队列中
     
 #     q.put(None)     #  向队列中放入一个空值(或者说是生产一个空值),空值也是值,是一个特殊的值




 #=================================




 # #生产消费模型  队列  演示一个子进程既可以put 也可以get
 # from multiprocessing import Queue
 # from multiprocessing import Process
 # import time


 # #消费者模型
 # def consumer(input_q):  #input_q  声明参数  从生产者那里拿走物品(数据,队列数据)
 #     while True:
 #         item = input_q.get()
 #         if item == None:       #用None作为标志,判断生产者是否已经结束了生产
 #             # input_q.put(6)
 #             break
 #         print(item)


 # #生产者逻辑
 # def producer(sequence,output_p):


 #     for i in sequence:
 #         time.sleep(1)
 #         output_p.put(i)


 # if __name__ == '__main__':
 #     q= Queue()
 #     con_p = Process(target=consumer,args=(q,))  #消费者进程 创建一个进程,进程的目标一定是个函数名,或者值类中的函数名即方法名,进程的参数
 #     con_p.start()


 #     sequence =[1,2,3,4,5]
 #     # pro_p = Process(target=producer,args=(sequence,q))  #消费者进程
 #     # pro_p.start()
 #     producer(sequence,q)  #  生产者开始生产数字12345,放入队列中
     
 #     # con_p.join()    #一定等子进程结束,保证consumer也能向队列中添加数字6 表明对列中子进程的双方既可以put,也可以get,而管道只能单向,一个子进程在定义管道后只能get或者put
 #     q.put(None)     #  向队列中放入一个空值(或者说是生产一个空值),空值也是值,是一个特殊的值




 #===============================================================================================


 # #管道操作-仅了解
 # from multiprocessing import Pipe
 # from multiprocessing import Process


 # #消费者模型
 # def consumer(pipe):
 #     (conn1,conn2) = pipe #两个变量构成一个管道,管道是设置的参数pipe
 #     conn2.close()        #关闭管道的发送方!!!
 #     while True:
 #         try:
 #             item = conn1.recv()
 #             print(item)
 #         except EOFError:         #文件读取错误
 #             break
 #     print('consumer ending done')
 # #生产者逻辑
 # def producer(sequence,sendPipe):
 #     for i in sequence:
 #         sendPipe.send(i)




 # if __name__ == '__main__':
 #     (conn1,conn2) = Pipe()  #创建管道,conn1是接收方  conn2是发送方
 #     con_p = Process(target=consumer,args=((conn1,conn2),)) #创建消费者子进程,把管道(元组)作为参数传入;生产者为主进程
 #     con_p.start()


 #     conn1.close()  #关闭生产者的输出管道
 #     sequence =[1,2,3,4,5]   #这里还要用到发送方
 #     producer(sequence,conn2)
 #     conn2.close()






 #=================================


 # #管道操作- 仅了解
 # from multiprocessing import Pipe
 # from multiprocessing import Process




 # #消费者模型
 # def consumer(pipe):
 #     (conn1,conn2) = pipe 
 #     conn2.close()
 #     while True:
 #         try:
 #             item = conn1.recv()
 #         except EOFError:
 #             conn1.close()
 #             break
 #         print(item)
 #     print('consumer ending done')


 # #生产者逻辑
 # def producer(sequence,sendPipe):
 #     for i in sequence:
 #         sendPipe.send(i)




 # if __name__ == '__main__':
 #     (conn1,conn2) = Pipe()  #创建管道,conn1是接收方  conn2是发送方
 #     con_p = Process(target=consumer,args=((conn1,conn2),)) #创建消费者子进程,把管道(元组)作为参数传入;生产者为主进程
 #     con_p.start()


 #     conn1.close()  #关闭生产者的输出管道
 #     sequence =[1,2,3,4,5]   #这里还要用到发送方
 #     producer(sequence,conn2)
 #     conn2.close()


 #===============================================================================================


 # #银行存取款demo1 正常


 # from multiprocessing import Process
 # from multiprocessing import Value   #在不同的进程间共享的变量
 # import time


 # def deposit(money):    #存钱
 #     for i in range(100):
 #         money.value += 1


 # def withdraw(money):   #取钱
 #     for i in range(100):
 #         money.value -= 1


 # if __name__ == '__main__':
 #     money = Value('i',2000) #共享变量 int 数值2000
 #     d = Process(target=deposit,args=(money,))
 #     d.start()
 #     w = Process(target=withdraw,args=(money,))
 #     w.start()
     
 #     d.join()
 #     w.join()


 #     print(money.value)    #三个进程一起跑 不一定会执行词句 需要等待子进程结束






 #=================================


 # #银行存取款demo1  - 存取款异常


 前提知识1:多进程不能访问同一个全局变量,原因是不同的进程使用的虚拟内存空间不同,而全局变量实际是用的同一个内存空间,
 因此需要 import Value 生成一个能够在不同的进程间共享和操作的变量


 前提知识2:对于time.sleep ,在一个程序中,子进程之间会抢占资源,比如抢占 value ,看a在睡醒的时刻是否能够抢占到资源value


 # from multiprocessing import Process
 # from multiprocessing import Value   #在不同的进程间共享的变量
 # import time


 # def deposit(money):    #存钱
 #     for i in range(100):
 #         time.sleep(0.1)
 #         money.value += 1


 # def withdraw(money):   #取钱
 #     for i in range(100):
 #         time.sleep(0.1)
 #         money.value -= 1


 # if __name__ == '__main__':
 #     money = Value('i',2000) #共享变量 int 数值2000
 #     d = Process(target=deposit,args=(money,))
 #     d.start()
 #     w = Process(target=withdraw,args=(money,))
 #     w.start()
     
 #     d.join()
 #     w.join()


 #     print(money.value)    #三个进程一起跑 不一定会执行词句 需要等待子进程结束




 #=================================


 #银行存取款demo2 - 存取款异常-解决 —— 锁1
 from multiprocessing import Process
 from multiprocessing import Value   #在不同的进程间共享的变量
 from multiprocessing import Lock
 import time


 def deposit(money,lock):    #存钱
     # lock.acquire()   #上锁的操作
     for i in range(100):
         time.sleep(10)
         money.value += 1
     # lock.release()


 def withdraw(money,lock):   #取钱
     # lock.acquire()   #上锁的操作
     for i in range(100):
         time.sleep(0.0001)
         money.value -= 1
     # lock.release()


 if __name__ == '__main__':
     money = Value('i',2000) #共享变量 int 数值2000
     lock = Lock() #银行为了安全 加了一把互斥锁


     d = Process(target=deposit,args=(money,lock))
     d.start()
     w = Process(target=withdraw,args=(money,lock))
     w.start()
     
     d.join()
     w.join()


     print(money.value)    #三个进程一起跑 不一定会执行词句 需要等待子进程结束




 #=================================


 # #银行存取款demo3 - 存取款异常-解决 —— 锁2 -更优 因为锁的力度更小,时间更短
 # from multiprocessing import Process
 # from multiprocessing import Value   #在不同的进程间共享的变量
 # from multiprocessing import Lock
 # import time


 # def deposit(money,lock):    #存钱
     
 #     for i in range(100):
 #         time.sleep(0.1)
 #         lock.acquire()   #上锁的操作
 #         money.value += 1
 #         lock.release()


 # def withdraw(money,lock):   #取钱


 #     for i in range(100):
 #         time.sleep(0.1)
 #         lock.acquire()   #上锁的操作
 #         money.value -= 1
 #         lock.release()


 # if __name__ == '__main__':
 #     money = Value('i',2000) #共享变量 int 数值2000
 #     lock = Lock() #银行为了安全 加了一把互斥锁


 #     d = Process(target=deposit,args=(money,lock))
 #     d.start()
 #     w = Process(target=withdraw,args=(money,lock))
 #     w.start()
     
 #     d.join()
 #     w.join()


 #     print(money.value)    #三个进程一起跑 不一定会执行词句 需要等待子进程结束,因此添加join方法