队列,管道,manager模块

###生产者消费者关系###

  主要是解耦(高内聚,低耦合),借助队列来实现生产者消费者 模型

  栈:先进后出(First In Last Out 简称:FILO)

  队列:先进先出(First In First Out 简称:FIFO)

  import queue  .............不能进行多进程之间的数据传输

1,队列:from multiprocessing import Queue借助Queue来解决生产者消费者模型,队列是安全的

  1.1>q = Queue(num)也只能是数据一次次的放,一次次的拿(一进一出)

    num:队列的最大长度(表示对列里能刚的最多数据,当数据量较大时就会阻塞,等待进入到队列中)

    q .get():表示获取队列中的数据,如果队列中有数据是直接获取,此时就没有阻塞等待这么一说了,当队列没有数据时,它就会在这阻塞等获取数据.

    q.put():表示向管道里发送数据,当管道数据未满,(管道里被获取数据的速度大于发送的速度时,)这时就可以直接放到队列里,如果管道数据满(管道获里被获取数据的速度小于发送的速度时)发送端(生成者)这时就会处于阻塞状态

    q.get_nowait():不阻塞:队列里有数据时就直接获取,没有时就会直接报错(比较敏感,不能容忍)

    q.put_nowait():,不阻塞:,如果可以继续往队列中放数据,就直接放,不能就会报错(比较敏感,不能容忍)

  1.2>JoinableQueue###可连接的队列

    from multiprocessing import JoinableQueue是继承了Queue,所以可以使用Queue中的方法

    并且JoinableQueue又多了两个方法

    q.join():用于生产者.表示等待消费者q.task_done返回一个标识(ack),生产者就能获得消费者当前消费了多少个数据

    q.task_done()#用于消费者,是指每个消费队列中的一个数据,就给join返回一个标识

###第一种方法###是在生产者q.put(None)来给消费者提示队列的数据被消费完.(是子进程与子进程之间的通信)

  from multiprocessing import Process,Queue..............导入队列的模块Queue

  def consumer(q):.....................................定义消费者函数来生成在消费者的子进程

    num = q.get()....................................通过q.get()来获取队列里的数据

    if num == None............................判断当num的数据是None的时候就执行下边的代码

      print("队列空了...")......

    else:.................................................当条件不成立的时候就打印这个数

      print(num)

  def producer(q):.......................................定义来生成生产者的子进程

    for i inrange(10):............................连续生产10个数

      num = i+1

      q.put(num)..............................把生产出来的数放到队列里

    q.put(None)....................................当数据生产完毕,就在队列里放一个None

  if __name__ == "__main__":

    q = Queue().........................................实例化一个队列的对象,括号里可以放数,表示队列可以放多少数据

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

    pro = Process(target=producer,args=(q,))

    con.start()

    pro.start()

###第二种方法###在主程序q.put(None)来控制消费者是否全部去到了生产者的数据(主进程和子进程之间的通信)

  from multiprocessing import Process,Queue

  def consumer(q):

    while 1:

      q = q.get()

      if num == None:

        print("队列空了...")

      else:

        print(num)

  def producer(q):

    for i in range(10):

      num = i + 1

      q.put(num)

  if __name__ == "__main__":

    q = queue()

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

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

    pro3 = Process(target=producer,args=(q,))

    pro1 = Process(target=producer,args=(q,))

    pro2 = Process(target=producer,args=(q,))

    con1.strat()

    con2.start()

    pro3.start()

    pro1.start()

    pro2.start()

    pro1.join()...............分别把生产者join主,等全部的生产者再执行主程序执行以下的程序时为了

    pro2.join()         每个消费者一个提示,队列里没有数据了(这应该用列表推导式)

    pro3.join()

    q.put(None)....................有几个消费者就q.put(None)几个

    q.put(None)....................有几个消费者就q.put(None)几个

###第三种方法###是通过JoinableQueue来实现子进程和子进程和主进程之间相互通信

  from multiprocessing import JoinableQueue,Process....导入一个新模块JoinableQueue

  def consumer(q):

    num = q.get()

    print(num)shi 

    q.task_done()................task_done是没get()到一个值就会返回给join(生产者)一个标识

  def producer(q):

    for i in range(10):

      num = i +1

      q.put(num)

    q.join()..............................等待全部接受完task_done生产者才完完全全结束(此时是阻塞等待)

  if __name__ == "__main__":

    q = JoinableQueue():

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

    pro = Process(target=producer,args=(q,))

    con.daemon = True

    con.start()

    pro.start()

    pro.join().............等到生产者的代码执行完毕,再开始执行主程序的代码,当主程序执行完毕就会把设置成守护进程停止,这时会强制关停守护进程的的while循环.

###主程序等待生产者程序只想完毕再执行,生产者程序会等待消费者程序执行完毕才执行完毕,这时主城序的执行完毕,又会将消费者程序强制停止,形成一个关系作用环

2,管道 

  2.1>单进程下的管道

    from multiprocessing import Pipe

    con1,con2 = Pipe()

    con1.send("liangxue")

    print(con2.recv()).................此时打印的是abc,con1发送的只能是con2接收

    con2.send([1,2,3])

    print(con1.recv())..................此时打印的是[1,2,3]con2发送只能是con1发送

    

###不能con1发送,con1接收时不会包错,发送端不能做为接收端### 

  2.2>多进程下的管道(管道都有2端,一端接收,一端发送)

    from multiprocessing import Process,Pipe导入Process模块和Pipe模块

    def func(con1,con2):..................定义一个创建子进程的函数

      con1.close()...............如果用con2发送,就把con1关掉,要不然会一直处于阻塞状态

      while 1:

        try:...............................是用抛异常机制来从管道取东西

          print(con2.recv())

        except EOFError:

          con2.close()......取完数据数据以后就把con2关掉 ,要不然会一直处于阻塞状态

          break.......................跳出循环,要不然会一直死循环

    if __name__ == "__main__":

      con1,con2 = Pipe()............................实例化的管道得到的是2个对象(管道的特性)

      p = Process(target=func,args=(con1,con2))

      p.start()

      con2.close()..................这个其实不用去关,不会处于阻塞状态,但为了代码的严谨,要关掉

      for i in range(10):

        con1.send(i)

      con1.close()....................这个必须关掉,要不接受端一直处于阻塞状态.

3,多进程之间的内存资源共享

  from multiprocessing import Process Manager...............导入Manager模块

  def func():..........................定义一个创建 子程序的函数

    num[0] -= 1..................................把可迭代对象(列表)的第0项数字减一

    print("子进程中的num的值是",num)

  if __name__ == "__main__":

    m = Manager()...........................实例化Manager这个对象

    num = m.list([1,2,3])........................共有资源列表,固定写法:m.数据类型()

    p = Process(target=func,args=(num,))

    p.start()

    p.join().........等子进程把共有的资源修改完再执行下一步操作,要不然会报错,数据容易混乱

    print("父进程中的num的值是",num)

4,进程池:一个存放有一定数量进程的池子,这些进程一直处于待命状态,一旦有任务来,马上就有进程去处理.因为在实际业务中,任务量是有多有少的,如果任务量特别的多,不可能要开对应的进程,第一,开启进程需要大量 的时间让操作系统来为你管理它,其次还需要消耗大量时间让cpu帮你调度

进程池的优点:会帮助程序员去管理进程池中的进程池\

进程池的最佳开启数量:核数+1,核数可以由os模块去get到,进程池的进程均为子进程,不用.start(),进程池会帮你开启进程池

  from multiprocessing import pool

  p = Pool(os.cpu_count() + 1)

  4.1>map方法:map(function,iterable)

    function:进程池中的进程执行的任务函数

    iterable:可迭代对象,是把可迭代对象中的每个元素依次传给任务函数当参数

    from multiprocessing import Pool....................导入Pool这个数据池

    def func(num):

      num = num + 1.........................把map中可迭代对象的每一个值传过来做处理

      print(num)

      return num...................此时return的每一个值(经过处理后)都会在此放到列表中

    if __name__ == "__main__":

      p = Pool(5)...................................实例化5个进程的数据池

      ret = p.map(func,[i for i in range(10)]).这的可迭代对象会把每一个数据作为参数传给函数

      p.close()..............关闭进程池的大门,不允许其他任务再进入到进程池,防止进程处理混乱

      p.join().....................等待进程池中的数据处理完毕再执行主进程代码

      print("主进程中的map的返回值是",ret)

  4.2>apply(function,args=()):表示同步的效率,也就是说进程池中的内容一个一个的去执行

   function:进程池中的进程执行的任务函数,args:可迭代对象的参数,是传给任务函数的参数

   同步处理任务时,不需要close()和join

   同步处理任务时,进程池中的所有进程是普通进程(主进程需要等待其执行结束)

    appy_async(func,args=(),callback=None):表示异步的效率,也就是说进程池中的进程一次性都去执行任务

   func:进程池中的进程执行的任务函数

   args:可迭代对象的参数,是传给任务函数的参数

   callback:回调函数,就是说没当进程池中有进程处理完了,返回的结果可以交给回调函数,由回调函数进行进一步的处理,回调函数只有异步有,同步是没有的

   异步处理任务时,进程池中的所有进程是守护进程(主进程代码执行完毕守护进程就结束)

   异步处理任务时,必须加上close和join

   回调函数的使用:

    进程的任务函数的返回值,被当成回电函数的形参接收到,以此进行进一步的处理操作

    回调函数是由主进程调用到的,而不是子进程,子进程值负责把结果传递给回调函数

  4.2.1>apply同步效率(结果是一个一个出的,因此效率比较低下,比较耗时)

    from multiprocessing import Pool

    def func(num):

      time.sleep(0.5)

      num += 1

      print(num)

    if __name__ == "__main":

      p = Pool(5),....................实例化一个5个进程的进程池(这5个进程池都是普通子进程)

      for i in range(10):

        p.apply(func,args=(i,))..................p.apply(上边的执行函数,是可迭代对象的参数)

      p.close()

      p.join()

  当加上p.close()时,在p.join()上边还好,不会报错,因为关闭了进程池的大门,所以join与不join每没有太大区别,当p.close()在p.join()的下一道程序,就会报错(程序执行到最后一个值的时候)报一个断言的错误,按时代码会执行完 

  4.2.2>异步的效率(异步是因为同时进行进程中的几条进程,所以耗时少,效率较高)

    def func(num):

      time.sleep(0.5)

      num += 1

      print(num)

    if __name__ == "__main__":

      p = Pool(5)..........................实例化一个放5个进程的进程池(实守护进程例化的进程是)

      for i in range(10):

        p.apply_async(func,args=(i,).....)p.apply_async(上边执行的函数,可迭代对象的参数)

      p.close()...................这必须有了,对于进程池的进程和数据比较安全

      p.join().............join主,因为开启的子进程都是守护进程,不join主,守护进程就不会执行了

这时的close和join就必须得加上了, 且顺序不能乱,,要么包一个断言的错误,要么就是代码执行完,每有打印任何结果,

  2.2.3>回调函数(进程的任务函数返回值,被当做是参数返回给回调函数,当做回调函数的参数)来进一步处理

  from multiprocessing import Pool..................导入Pool进程池

  def finc(num):........................定义一个进程的任务函数

    num += 1..............................操作进程处理来的数据

    return num...............................此时返回给回调函数,并做为回调函数的参数

  def cal_back(num):.............................定义回调函数

    num = num + 10.................................操作进程任务函数返回来的参数

    print(num)

  if __name__ == "__main__":

    p = Pool(5).....................实例化一个存放有5个进程的进程池

    for i in range(10):.................传原始数据

      p.apply_async(func,args=(i,),callback=cal_back)三个参数:进程的任务函数,穿的原始参数,                                                                                                                    回调函数

    p.close()

    p.join()

进程池异步处理(一次性处理进程池里的相应数量的进程)时间利用率较高,而同步处理即使进程池里有一定数量的进程,也是一条一条的去执行,因此时间利用率相对较低

    

 

  

      

      

   

    

        

      

    

        

     

     

    

  

  

    

    

    

  

      

         

      

      

  

    

    

  

猜你喜欢

转载自www.cnblogs.com/ljc-0923/p/9632568.html
今日推荐