• python queue, pipe, manage


    线程中的Queue

     1 import time
     2 import threading
     3 import queue
     4 import random
     5 
     6 def putMessage():
     7     for i in "Hello World!!!":
     8         q.put(i)
     9         time.sleep(random.random())
    10         # print("size:%s"%q.qsize())            # 查看队列长度
    11         #
    12         # print("full:%s"%q.full())             # 查看队列是否为满的状态
    13         #
    14         # print("empty:%s"%q.empty())        # 查看队列是否为空的状态
    15 
    16 
    17 def getMessage():
    18     while True:
    19         if not q.empty():
    20             print(q.get())
    21         else:
    22             time.sleep(random.random())
    23 
    24 
    25 if __name__ == "__main__":
    26     q = queue.Queue()
    27 
    28     t1 = threading.Thread(target=putMessage)
    29     t1.setDaemon(True)
    30     t1.start()
    31 
    32     t2 = threading.Thread(target=getMessage)
    33     t2.setDaemon(True)
    34     t2.start()
    35 
    36     time.sleep(10)

    进程中的Queue

     1 from multiprocessing import Queue
     2 
     3 q = Queue(3)    # 初始化一个Queue对象,最多可以put三条信息,如果不写3,那么久无限制
     4 
     5 q.put("Message01")         # 添加信息的方法
     6 q.put("Message02")
     7 print(q.full())          # 查看 队列 是否满了的方法
     8 
     9 q.put("Message03")
    10 print(q.full())
    11 
    12 # 因为队列已经满了,所以下面的消息会出现异常,第一个 try 会等待2秒后再抛出异常,
    13 # 第二个 try 会立刻抛出异常
    14 try:
    15     q.put("Message04", True, 2)
    16 except:
    17     print("消息队列已满,现有消息数量:%s"%q.qsize())
    18 
    19 try:
    20     q.put_nowait("Message04")
    21 except:
    22     print("消息队列已满,现有消息数量:%s"%q.qsize())
    23 
    24 # 推荐使用的方式,先判断队列是否已满,再写入
    25 if not q.full():
    26     q.put_nowait("Message04")
    27 
    28 # 读取消息的时候,先判断消息队列是否为空,再读取
    29 if not q.empty():
    30     for i in range(q.qsize()):
    31         print(q.get_nowait())

    队列:
      为什么要用队列?列表也很好用啊。:数据安全
      创建方法:
        模式1:FIFO -- queue.Queue()
        模式2:FILO -- queue.LifoQueue()
        模式3:priorty -- queue.PriorityQueue()
          q.put([1, 'hello'])
          q.put([2, 'world'])
          级别 1 比 2 低, 1 先出来

      方法的参数:
        put()
          调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常
        get()
          调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。

      其它方法:
        q.empty() 如果队列为空,返回True,反之False
        q.full() 如果队列满了,返回True,反之False
        q.full 与 maxsize 大小对应
        q.get([block[, timeout]]) 获取队列,timeout等待时间
        q.get_nowait() 相当q.get(False)
        非阻塞 q.put(item) 写入队列,timeout等待时间
        q.put_nowait(item) 相当q.put(item, False)
        q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号

        q.join() 实际上意味着等到队列为空,再执行别的操作
        # join多少次,就需要用几次 task_done

    多进程优点:

      1. 可以利用多核实现并行运算

    缺点:

      1. 开销大
      2. 通信困难

    管道Pipe

    multiprocessing.Pipe([duplex])
    返回2个连接对象(conn1, conn2),代表管道的两端,
    默认是双向通信.如果duplex=False,conn1只能用来接收消息,conn2只能用来发送消息.

    主要用到的方法:
    send() 发送数据
    recv() 接收数据
     1 import multiprocessing
     2 
     3 
     4 from multiprocessing import Process, Pipe
     5 
     6 def send(pipe):
     7     pipe.send(['spam'] + [42, 'egg'])
     8     pipe.close()
     9 
    10 def talk(pipe):
    11     pipe.send(dict(name = 'Bob', spam = 42))
    12     reply = pipe.recv()
    13     print('talker got:', reply)
    14 
    15 if __name__ == '__main__':
    16     (con1, con2) = Pipe()
    17     sender = Process(target = send, name = 'send', args = (con1, ))
    18     sender.start()
    19     print("con2 got: %s" % con2.recv())#从send收到消息
    20     con2.close()
    21 
    22     (parentEnd, childEnd) = Pipe()
    23     child = Process(target = talk, name = 'talk', args = (childEnd,))
    24     child.start()
    25     print('parent got:', parentEnd.recv())
    26     parentEnd.send({x * 2 for x in 'spam'})
    27     child.join()
    28     print('parent exit')

    进程间的信息共享Manage

    Python中进程间共享数据,处理基本的queue,pipe外,还提供了更高层次的封装。使用multiprocessing.Manager可以简单地使用这些高级接口。

    Manager支持的类型有list,dict,Namespace, Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。
     1 import multiprocessing
     2 import time
     3 
     4 
     5 def worker(d, key, value):
     6     d[key] = value
     7 
     8 if __name__ == '__main__':
     9     mgr = multiprocessing.Manager()
    10 
    11     d = mgr.dict()
    12     jobs = [multiprocessing.Process(target=worker, args=(d, i, i*2))
    13              for i in range(10)
    14              ]
    15     for j in jobs:
    16         j.start()
    17     for j in jobs:
    18         j.join()
    19     print('Results:' )
    20     for key, value in enumerate(dict(d)):
    21         print("%s=%s:%s" % (key, value, d[value]))
    22 
    23 
    24     print("================================================================")
    25 
    26     manager = multiprocessing.Manager()
    27     Global = manager.Namespace()
    28     Global.x = 10
    29     Global.y = 'hello'
    30     print(Global)
    31 
    32     print("==================================================================")
    问题:

    列表不可变
    在学习python多进程管理manager时候,当不使用join对当前进程(主进程)进行阻塞时会报错:

    这样进行一下总结:在使用manager管理/进行多进程及其数据交互时候,必须对每一个manager内的进程进行join-------待所有子进程完成后再回到主进程。

    多进程之进程池

     1 import time
     2 from multiprocessing import Pool
     3 
     4 def worker():
     5     for i in range(10):
     6         print("From worker %s"%i)
     7         time.sleep(0.5)
     8 
     9 def foo():
    10     for i in range(10):
    11         print("From foo %s"%i)
    12         time.sleep(0.5)
    13 
    14 def bar():
    15     for i in range(10):
    16         print("From bar %s"%i)
    17         time.sleep(0.5)
    18 
    19 if __name__ == "__main__":
    20     pool = Pool(4)            # 创建Pool对象, 3 表示同时最多可以增加 3 条进程
    21     pool.apply_async(worker)
    22     pool.apply_async(worker)
    23     pool.apply_async(worker)
    24     pool.apply_async(foo)
    25     pool.apply_async(foo)
    26     pool.apply_async(foo)
    27     pool.apply_async(bar)
    28     pool.apply_async(bar)
    29     pool.apply_async(bar)
    30 
    31     pool.close()                  # 关闭进程池,禁止添加任务
    32     pool.join()          # 等待子进程结束后,主进程才往下走
    33     print("Is done...")

    并发之协程

     1 import time
     2 
     3 def consumer():
     4     r = ''
     5     while True:
     6         # 3、consumer通过yield拿到消息,处理,又通过yield把结果传回;
     7         #    yield指令具有return关键字的作用。然后函数的堆栈会自动冻结(freeze)在这一行。
     8         #    当函数调用者的下一次利用next()或generator.send()或for-in来再次调用该函数时,
     9         #    就会从yield代码的下一行开始,继续执行,再返回下一次迭代结果。通过这种方式,迭代器可以实现无限序列和惰性求值。
    10         n = yield r
    11         if not n:
    12             return
    13         print('[CONSUMER] ←← Consuming %s...' % n)
    14         time.sleep(1)
    15         r = '200 OK'
    16 def produce(c):
    17     # 1、首先调用c.next()启动生成器
    18     next(c)
    19     n = 0
    20     while n < 5:
    21         n = n + 1
    22         print('[PRODUCER] →→ Producing %s...' % n)
    23         # 2、然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
    24         cr = c.send(n)
    25         # 4、produce拿到consumer处理的结果,继续生产下一条消息;
    26         print('[PRODUCER] Consumer return: %s' % cr)
    27     # 5、produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
    28     c.close()
    29 if __name__=='__main__':
    30     # 6、整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
    31     c = consumer()
    32     produce(c)

    协程封装之greenlet

     1 import greenlet
     2 import time
     3 import random
     4 
     5 """
     6 创建方法:greenlet.greenlet(self, run=None, parent=None)
     7 主要方法:
     8         a.switch()    切换到 a 里面执行
     9 """
    10 def foo():
    11     for i in range(10):
    12         print("foo:",i)
    13         time.sleep(random.random())
    14         gb.switch()
    15 
    16 
    17 def bar():
    18     for i in range(10):
    19         print("bar:", i)
    20         time.sleep(random.random())
    21         gf.switch()
    22 
    23 if __name__ == "__main__":
    24     gf = greenlet.greenlet(foo)
    25     gb = greenlet.greenlet(bar)
    26 
    27     gf.switch()

     

    协程封装之 gevent

     1 import gevent
     2 from gevent import monkey
     3 import time
     4 import random
     5 
     6 monkey.patch_all()      #  如果遇到 IO 阻塞,那么就切换到下一个 协程的程序
     7 
     8 def foo():
     9     for i in range(10):
    10         print("foo:",i)
    11         time.sleep(random.random())
    12 
    13 
    14 def bar():
    15     for i in range(10):
    16         print("bar:", i)
    17         time.sleep(random.random())
    18 
    19 
    20 if __name__ == "__main__":
    21     gevent.joinall([gevent.spawn(foo),
    22                     gevent.spawn(bar)])
    23 
    24 
    25     # 固定用法,将里面的函数放入到 协程的执行序列中
  • 相关阅读:
    Python之旅.第十章.mysql..
    Python之旅.第十章.mysql.
    Python之旅.第十章.mysql.
    Python之旅.第十章.mysql。
    Mac 移动光标和删除
    网络编程——socket开发
    闭包(closure)
    命名空间 and 作用域
    Function
    for循环的禁忌
  • 原文地址:https://www.cnblogs.com/alwaysInMe/p/7211927.html
Copyright © 2020-2023  润新知