ZeroMQ学习笔记(1)——基础知识

第一章 基础知识

解释zmq:
1、 像有路由的邮箱 很快
2、 更小巧,更简单
代码与代码之间必须要有交流,像人脑一样亿万个神经元相互发射消息
互联方式:
很多IETF规范,例如HTTP,但只考虑大型服务器和C/S
集中:UDP,TCP,专有协议,HTTP和WebSocket
分布: Skype, BT
Fixing the World:

  1. 如何将任何地方的任何代码连接起来
  2. 包装在人们容易理解和使用尽可能简单的构件中
    模式一:请求应答模式REQ-REP
    对应于RPC(远程过程调用)和C/S模型
    REQ-REP步调一致(一次交流):
    Server 先 zmq_recv 后 zmq_send
    Client 先 zmq_send 后 zmq_recv
    服务器中断后,重启服务器,客户端无法恢复正常。
    示例1-1 “Hello World” 服务器

coding=gbk

import zmq
import time

准备上下文

context = zmq.Context()

与客户端交流的套接字

socket = context.socket(zmq.REP)

将REP套接字绑定到tcp://127.0.0.1:55555

socket.bind(“tcp://127.0.0.1:5555”)

while True:
# 等待来自客户端的请求
message = socket.recv()
print(“Received request: %s” % message)
time.sleep(1)
# 给客户端发送回复
socket.send(b"World")
示例1-1 “Hello World” 客户端

coding=gbk

import zmq

准备上下文

context = zmq.Context()
print(“Connecting to hello world server…”)

与服务器交流的套接字

socket = context.socket(zmq.REQ)

将REQ套接字连接到tcp://127.0.0.1:55555

socket.connect(“tcp://127.0.0.1:5555”)

for i in range(10):
print(“Sending request %s …” % i)
socket.send(b"Hello")
message = socket.recv()
print(“Received reply %s [ %s ]” % (i, message))

补充:
上下文:context = zmq.Context()
套接字:socket = context.socket(zmq.**)

ZMQ对发送的数据只知字节大小,不知内容
复杂的数据类型和对象 有专门的库 如(协议缓冲区)
字符串:
C:字符串用空字节终止,“Hello” H e l l o 0 (6)
Python:“Hello” H e l l o (5)
zmq字符串中:“指定长度” ,在线路上发送时,不含结尾空字符。
C语言使用zmq传递字符串需要包含”zhelpers.h“头文件
版本报告:示例version.zmq

模式二:发布订阅模式PUB-SUB
示例: Weather update PUB

coding=gbk

import zmq
import random
import time

from random import randrange

context = zmq.Context()
publisher = context.socket(zmq.PUB)
publisher.bind(“tcp://127.0.0.1:5555”)

while True:
# 邮编 温度 湿度
zipcode = random.randrange(1, 100000)
temperature = random.randrange(-80, 135)
humidity = random.randrange(10, 60)
time.sleep(1)
publisher.send_string("%i %i %i" % (zipcode, temperature, humidity))
示例: Weather update SUB

coding=gbk

import zmq
import sys
context = zmq.Context()
subscriber = context.socket(zmq.SUB)
print(“Collecting updates from weather server…”)
subscriber.connect(“tcp://127.0.0.1:5555”)

订阅者订阅所有主题

subscriber.setsockopt_string(zmq.SUBSCRIBE, ‘’)
while True:
message = subscriber.recv_string()
zipcode, temperature, humidity = message.split()
print("%s %s %s" % (zipcode, temperature, humidity))

SUB收集针对邮编的1000个update后计算avg,退出
单向的数据发布
使用SUB套接字必须用zmq_setsockopt()和SUBSCRIBE()设置一个订阅,订阅者可以设置许多订阅。
PUB-SUB 异步
bind PUB 服务端(发布方)只能Send
connect SUB 客户端(订阅方)只能Recv
Slow joiner(慢木匠,慢连接):
顺序:SUB连接到端点,并接收。PUB绑定端点,立即发出消息。
启动SUB,稍后在启动PUB,依然总会错过PUB的第一条消息。原因是,订阅者SUB连接到PUB时,PUB可能已经将消息发出去了。
类似的,TCP建立连接,需花费几毫秒握手。解决慢连接的问题。
采用休眠的方法既缓慢又脆弱。
示例代码同步问题的替代方法是PUB消息无限,SUB不关心启动前发生了什么。
重启PUB端任意次,SUB端将继续工作。
补充
1、 一个SUB可以连接多个PUB,每次使用一个connect()调用。数据将交错(公平排队)。没有一个发布者可以淹没其他发布者。
2、 一个PUB没有SUB,会简单丢弃所有消息
3、 使用TCP且SUB慢速,PUB处消息会排队,用“高水位线“针对此情况,保护SUB
4、 ZMQ 3.x开始(tcp或ipc)过滤器发生在PUB
epgm 过滤器发生在SUB
ZMQ 2.x 所有协议 过滤器都在SUB

模式三 PULL-PUSH
并行任务发生器:产生100个任务,每个任务包含一条消息(休眠毫秒数)
并行任务工人 :接受一个消息,按消息里的秒数休眠,然后发出完成信号
并行任务接收器:收集100个结果消息,计算整体时间
示例并行任务发生器:

coding=gbk

import zmq
import random
import time

context = zmq.Context()
sender = context.socket(zmq.PUSH)
sender.bind(“tcp://127.0.0.1:5555”)

sink = context.socket(zmq.PUSH)
sink.connect(“tcp://127.0.0.1:5556”)

print("Press Enter when the workers are ready: ")
_ = input()
print(“Sending tasks to workers…”)
sink.send(b’0’)

random.seed()
total_msec = 0
for task_nbr in range(100):
workload = random.randint(1, 100)
total_msec += workload

sender.send_string(u'%i' % workload)

print(“Total expected cost: %s msec” % total_msec)

time.sleep(1)

示例并行任务工人:

coding=gbk

import zmq
import time
import sys

context = zmq.Context()
receiver = context.socket(zmq.PULL)
receiver.connect(“tcp://127.0.0.1:5555”)

sender = context.socket(zmq.PUSH)
sender.connect(“tcp://127.0.0.1:5556”)

while True:
s = receiver.recv()
sys.stdout.write(’.’)
sys.stdout.flush()

time.sleep(int(s)*0.001)

sender.send(b'')

示例并行任务接收器:

coding=gbk

import zmq
import sys
import time

context = zmq.Context()

receiver = context.socket(zmq.PULL)
receiver.bind(“tcp://127.0.0.1:5556”)

s = receiver.recv()

tstart = time.time()

for task_nbr in range(100):
s = receiver.recv()
if task_nbr % 10 == 0:
sys.stdout.write(’:’)
else:
sys.stdout.write(’.’)
sys.stdout.flush()

tend = time.time()
print("Total elapsed time: %d msec" % ((tend - tstart)*1000))

1、 工人向上连接发生器,向下连接接收器
2、 同步开始,同批次所有工人启动运行。
3、 发生器PUSH任务,均匀分配给工人,批处理前,工人都已连接(负载均衡)
4、 接收器PULL均匀收集工人的结果。(公平排队)
PULL-PUSH模式也会慢连接,影响负载均衡,某个工人连接的早,抓取的消息多。

用zmq编程
1、 zmq是一个api,有许多可能
2、 漂亮的代码风格
3、 边编程,边测试
4、 出bug时,代码分片段测试
5、 抽象(类,方法)不要只复制,要修改
获得正确的上下文
1、 创建一个上下文
2、 创建套接字
C语言中,进程中只创建并使用一个上下文
使用fork()时:主进程先执行zmq_ctx_new(),在fork(),子进程会获得自己的上下文,子进程干活,父进程管理。
执行彻底的退出:
C语言,要手动释放内存。Python:不用,内存自动释放。
多线程:不要在多线程中使用同一个套接字 (复杂)。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lcy~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值