qtcpsocket类read函数接收大数据_Python 进程线程:使用PIPE交换数据

b173f45dd99868046ece13f4e08da470.png
10305

进程之间交换对象

并行:同一时刻有多条指令在多个CPU上运行.

并行时常常需要进程之间交换数据,multiprocessing 模块提供了2个communication channels 来交换数据:队列queue 和管道pipe

281897d931902c19e450b0185b5b48b1.png

除了上面两种交换数据的方式之外,进程之间也可以使用同步原语进行数据交换,但是要尽可能的避免使用同步原语,例如锁.因为queuepipe效率上更高,更加安全.

1.使用队列queue 来交换数据

queue 是多进程安全的队列,可以使用queue 来实现多进程之间的数据传递.

  • put :此方法用来插入数据队列中,可选参数有两个:blocked\timeout
    • 如果blocked=True(默认值),并且timeout 为正数,该方法会阻塞timeout 指定时间.直到该队列有剩余的空间.如果超时,会抛出Queue.Full异常
    • 如果blocked=False,但是该队列已满,会抛出Queue.Full异常
  • get :此方法可以从队列读取并删除一个元素.可选参数有2个:blocked\timeout
    • 如果blocked=True(默认值),并且timeout 为正数,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常
    • 如果blocked=False,如果queue 有一个值可用,立即返回该值,否则,队列为空,会立即抛出异常Queue.Empty

常用属性和方法:

qsize()返回队列的大小
empty()返回布尔值,队列是否为空
full()返回布尔值,队列是否满了
put(item[,block[,timeout]])在队列中添加元素item
put_nowait(item)等价与put(item, False)
get(item[,block[,timeout]])在队列中删除元素并返回该元素的值
get_nowait()等价与get(Flase)
close()表示该queue 不加入新元素
join_theread()加入后台线程,只能在调用close() 后使用.它阻塞直到后台线程退出,确保缓冲区所有数据已经刷新到管道.默认情况下,如果进程不是队列的创建者,则退出.它将尝试加入队列的后台线程.
cancle_join_thread()终止join_thread()防止后台线程在进程退出时被自动连接,可能会导致数据丢失
队列实例
#!/usr/bin/env python
# encoding: utf-8

import multiprocessing,time,os,random

"""
queue队列
 在队列中,进程是相互独立的.数据的交互,可以使用队列一个写入,一个读取
"""

def write_process(q):
 for i in ['A', 'B', 'C', 'D']:
     print('put {} to queue ...'.format(i))
     q.put(i)
     time.sleep(random.random())

def read_process(q):
 while True:
     if not q.empty():
         value = q.get()
         print('get {} from queue...'.format(value))
         time.sleep(random.random())
     else:
         break

if __name__ == '__main__':
 """主进程"""
 # 使用主进程创建队列
 main_process_queue = multiprocessing.Queue()
 # 创建子进程
 write_process_child = multiprocessing.Process(target=write_process, args=(main_process_queue, ))
 read_process_child = multiprocessing.Process(target=read_process, args=(main_process_queue, ))
 # 启动并阻塞
 write_process_child.start()
 write_process_child.join()
 read_process_child.start()
 read_process_child.join()

执行结果:

put A to queue....
put B to queue....
put C to queue....
put D to queue....
Get A from queue
Get B from queue
Get C from queue
Get D from queue
生产者/消费者模式

以上就类似于生产者/消费者模式

它包含两类进程:一种只是用来生产数据,例外一种只是用来消费数据.为了串联他们,通常会采用共享的数据区域,就像一个仓库.生产者产生的数据都放入仓库中并不需要关注消费者的行为,消费者只需要从共享仓库中获取数据,并不需要关心生产者的行为.

而作为仓库关注的行为是:

  • 如果仓库共享数据区域已满的状态
  • 如果共享数据区域已空的状态
#!/usr/bin/env python
# encoding: utf-8

import multiprocessing,os,time,random

# 定义生产者
class Producer(multiprocessing.Process):
    def __init__(self, queue):
        self.queue = queue
        super(Producer, self).__init__()

    def run(self):
        for i in range(3):
            item = random.randint(0, 255)
            # 添加到队列
            self.queue.put(item)
            print('生产者进程:{},添加{}到Queue队列中...'.format(self.name, item))
            time.sleep(1)
            print('队列大小:{}'.format(self.queue.qsize()))

# 定义消费者
class Cunsumer(multiprocessing.Process):
    def __init__(self, queue):
        self.queue = queue
        super(Cunsumer, self).__init__()

    def run(self):
        while True:
            if not self.queue.empty():
                time.sleep(2)
                print('队列非空')
                item = self.queue.get()
                print('消费者进程:{},从队列中取出:{}'.format(self.name, item))
            else:
                print('队列为空,退出')
                break

if __name__ == '__main__':
    """主进程"""
    queue = multiprocessing.Queue()
    producer = Producer(queue)
    cunsumer = Cunsumer(queue)
    producer.start()
    producer.join()
    cunsumer.start()
    cunsumer.join()

运行结果

生产者进程:Producer-1,添加227到Queue队列中...
队列大小:1
生产者进程:Producer-1,添加114到Queue队列中...
队列大小:2
生产者进程:Producer-1,添加252到Queue队列中...
队列大小:3
队列非空
消费者进程:Cunsumer-2,从队列中取出:227
队列非空
消费者进程:Cunsumer-2,从队列中取出:114
队列非空
消费者进程:Cunsumer-2,从队列中取出:252
队列为空,退出

Queue 在其中扮演了一个仓库的角色,就是用来处理共享数据的

2.使用pipe 管道

Pipe 不是类,是函数,该函数定义在multiprocessing\connection.py 中,返回一对通过管道连接的对象con1con2,函数的原型是Pipe()duplex=True

  • dublex=True(默认值):管道是双向的,处于全双工模式,con1\con2 都可以收发数据
  • dublex=False ,管道是单向的,con1 只能用于发送,con2 只能用于接受
con1, con2 = multiprocessing.Pipe([duplex])

Pipe() 返回的是管道的两端,两端每个对象都有send()recv() 方法(还有其他方法),例如在全双工模式下,可以用con1.send() 发送消息,con2.recv()接受消息,如果没有消息可以接受,recv()方法会一直阻塞,如果管道已经关闭,recv() 会抛出EOFError 异常

常用方法:

send(obj)将一个对象发送到连接的另外一端
recv()返回一个由另一端send()的对象,该方法会一直阻塞直到接收到对象,如果对端关闭了连接,或者没有东西可以接受,将抛出EOFError
fileno返回由连接对象使用的描述符
close()关闭连接对象
poll()返回连接对象是否有可以读取的数据.
1.主进程和子进程管道通信

需要注意的是,管道在建立的时候自动连接了主进程,不管是使用全双工,还是半双工,都需要对主进程的管道进行处理.

在全双工模式中,假设主进程是发送端,子进程是接收端

"""全双工管道"""
import multiprocessing,time

def child_process(pipe):
 while True:
     try:
         time.sleep(1)
         num = pipe.recv()
         print('子进程:{},接收:{}'.format(multiprocessing.current_process().name, num))
         print('pipe管道状态', pipe.poll())
     except Exception:
         print('如果一端被关闭,另外一端接收完毕后,会报错')
         break

if __name__ == '__main__':
 """主进程"""
 recv_pipe, send_pipe = multiprocessing.Pipe(duplex=True)
 # 主进程即是发送端,也是接收端
 for i in range(5):
     send_pipe.send(i)
     print("主进程Pipe发送:{}".format(i))
 # 发送完毕后,关闭通道
 send_pipe.close()
 child_process_pipe = multiprocessing.Process(target=child_process, args=(recv_pipe, ))
 child_process_pipe.start()
 child_process_pipe.join()

执行结果:

主进程Pipe发送:0
主进程Pipe发送:1
主进程Pipe发送:2
主进程Pipe发送:3
主进程Pipe发送:4
子进程:Process-1,接收:0
pipe管道状态 True
子进程:Process-1,接收:1
pipe管道状态 True
子进程:Process-1,接收:2
pipe管道状态 True
子进程:Process-1,接收:3
pipe管道状态 True
子进程:Process-1,接收:4
pipe管道状态 True
如果一端被关闭,另外一端接收完毕后,会报错

反之,主进程也能当接收端,子进程当发送端.

关闭管道后,try 语句用于处理产生的EOFError 异常

2.主进程闲置,2个子进程一发一收

在全双工模式下,就算主进程闲置,主进程也连接在管道的一端,既可以在接收端,也可以在发送端.需要自己去选择把握.

import multiprocessing
import time


def proc1(pipe):
 for i in range(10):
     print('send: %s' % i)
     pipe.send(i)  # pipe.send 发送数据
     time.sleep(1)
 pipe.close()


def proc2(pipe):
 while True:
     try:
         print('proc2 recv:', pipe.recv())  # pipe.recv 用与接收数据
         time.sleep(1)
      except Exception:
         print('exit')
         break


if __name__ == '__main__':
  pipe1, pipe2 = multiprocessing.Pipe()
  p1 = multiprocessing.Process(target=proc1, args=(pipe1, ))
  p2 = multiprocessing.Process(target=proc2, args=(pipe2, ))
  p1.start()
  p1.join()
 # 在主进程端把发送pipe关闭
  pipe1.close()
  p2.start()
  p2.join()

关闭管道后,try 语句用于处理产生的EOFError 异常

- END -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值