在Python中,我可以选择使用“poller”对象来轮询阻塞套接字,以便在指定的毫秒数之后等待和解除阻塞消息(在下面的情况下,1000,在while块中):
import zmq
# now open up all the sockets
context = zmq.Context()
outsub = context.socket(zmq.SUB)
outsub.bind("tcp://" + myip + ":" + str(args.outsubport))
outsub.setsockopt(zmq.SUBSCRIBE, b"")
inreq = context.socket(zmq.ROUTER)
inreq.bind("tcp://" + myip + ":" + str(args.inreqport))
outref = context.socket(zmq.ROUTER)
outref.bind("tcp://" + myip + ":" + str(args.outrefport))
req = context.socket(zmq.ROUTER)
req.bind("tcp://" + myip + ":" + str(args.reqport))
repub = context.socket(zmq.PUB)
repub.bind("tcp://" + myip + ":" + str(args.repubport))
# sort out the poller
poller = zmq.Poller()
poller.register(inreq, zmq.POLLIN)
poller.register(outsub, zmq.POLLIN)
poller.register(outref, zmq.POLLIN)
poller.register(req, zmq.POLLIN)
# UDP socket setup for broadcasting this server's address
cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# housekeeping variables
pulsecheck = datetime.utcnow() + timedelta(seconds = 1)
alivelist = dict()
pulsetimeout = 5
while True:
polls = dict(poller.poll(1000))
if inreq in polls:
msg = inreq.recv_multipart()
if msg[1] == b"pulse": # handle pluse
ansi("cyan", False, textout = " pulse" + "-" + msg[0].decode())
if not msg[0] in alivelist.keys():
handlechange(msg[0])
alivelist[msg[0]] = datetime.utcnow() + timedelta(seconds = pulsetimeout)
if outsub in polls:
msgin = outsub.recv_multipart()[0]
repub.send(msgin) # republish
msg = unpacker(msgin)
if isinstance(msg, dict):
valu = msg.get("value")
print(".", end = "", flush = True)
else:
ansi("green", False, textout = msg)
if req in polls:
msg = req.recv_multipart()
valmsg = validate_request(msg)
if not valmsg[0]:
ansi("red", True); print(valmsg[1]); ansi()
elif len(alivelist) > 0:
targetnode = random.choice(list(alivelist.keys()))
inreq.send_multipart([targetnode, packer(valmsg[1])])
ansi("blue", True, textout = "sent to " + targetnode.decode())
else:
ansi("red", True, textout = "NO CONNECTED NODES TO SEND REQUEST TO")
if outref in polls:
msg = outref.recv_multipart()
destinataire, correlid = msg[1].split(b"/")
req.send_multipart([destinataire, correlid, msg[2]])
我想在Elixir(或Erlang)中实现类似的东西,但我首选的本机库chumak似乎没有实现轮询。我如何在Erlang / Elixir中实现非阻塞接收,最好是使用Chumak,但如果需要,我会转移到另一个Erlang zeroMQ库?我的套接字模式首选项是路由器发送,经销商收到
修改
我的用例如下。我有第三方金融服务,它根据请求提供数据,提供异步的答案。所以你可以发送多个请求,你会在一段不确定的时间后得到回复,而不一定按照你发送的顺序。
所以我需要将这项服务连接到Erlang(实际上是Elixir),ZeroMQ似乎很合适。连接(通过Phoenix)到Erlang / Elixir的多个用户将发送请求,我需要将这些用户传递给此服务。
如果其中一个请求出错,或者第三方服务出现某种问题,则会出现问题。我将阻止等待响应,然后无法处理来自Phoenix的新请求。
基本上我想不断听取新的请求,发送它们,但是如果一个请求没有产生响应,我的响应比请求少一个,这将导致永久等待。
据我所知,如果我单独发送请求,那么好的请求会产生响应,因此即使随着时间的推移,我发送的请求和收到的响应之间会有很大的数字差异,我也不需要担心阻塞。也许设计理念是我不应该担心这个?或者我应该尝试跟踪对请求的一对一响应并以某种方式超时无响应?这是一种有效的设计模式吗?
答案 0 :(得分:4)
您的系统是否经常连接到异步查询资源,或者您是否与每个查询建立新连接?
每种情况在Erlang中都有自己的自然模型。
案例:单个(或池)长期联系
维护与资源的会话的长期连接(与数据库的连接的工作方式)最自然地建模为系统中具有代表该外部资源的唯一任务的进程。
该过程的要求是:
erlang:send_after/3
更精确地完成当然,这意味着实现此过程的模块需要说出该资源的协议。但如果实现了这一点,那么就不需要像MQ应用程序这样的消息传递代理。
这允许你让 进程被激活并阻止接收,而你的程序的其余部分将继续执行任何操作。如果没有一些任意的轮询,肯定会让你进入计划问题的邪恶黑色沼泽。
案例:每个查询的新连接
如果对资源的每个查询都需要新连接,则模型类似,但在此处您为每个查询生成一个新进程,它代表系统中的查询。它会阻止等待响应(超时),其他任何事情都不重要。
实际上,这是更简单的模型,因为那时你不必擦除过去的,可能超时的请求列表,这些请求永远不会返回,不必与一组暂停的超时交互通过erlang:send_after/3
发送的消息,您将抽象更接近实际的问题模型。
您不知道这些查询何时会返回,这会导致一些潜在的混淆 - 因此将每个实际查询建模为生物是切断逻辑混乱的最佳方式。
无论哪种方式,自然地模拟问题:作为并发,异步系统
但是,在任何情况下,您是否希望以Python或C等方式进行轮询。这是一个并发问题,因此对其进行建模将为您提供更多的逻辑自由,并且更有可能产生一个缺少产生奇怪情况的角落的正确解决方案。