在python异步IO上发布订阅

在python异步IO上发布订阅,python,websocket,python-asyncio,Python,Websocket,Python Asyncio,我认为我的问题很简单也很愚蠢,但我读了很多资料,无法想象如何做我想做的事 所以,我使用websockets库,我有一个算法: # 1. get connection and start handle it async def main_request_handler(ws, path): proxy = Proxy() try: await proxy.start(ws, path) 二,。在start内部,我创建第二个websocket来传递来自ws的请求,并

我认为我的问题很简单也很愚蠢,但我读了很多资料,无法想象如何做我想做的事

所以,我使用
websockets
库,我有一个算法:

# 1. get connection and start handle it
async def main_request_handler(ws, path):
    proxy = Proxy()
    try:
        await proxy.start(ws, path)
二,。在start内部,我创建第二个websocket来传递来自
ws
的请求,并接收应答,将它们发送到
ws

while True:
    request_raw = await self.ws_server.recv()
    await self.process_request_from_server(request_raw)
问题是,我需要使用一个websocket服务器连接进行复制
ws
客户端,我需要从
ws\u服务器
向每个人传递相同的答案。现在我只得到一个响应,因为.recv()只返回其中一个“订阅者”的值。
如何解决这个问题?请注意,我使用的是
,而True
async
我不确定我是否理解正确,但多个协程不是你想要的吗

while True:
    request_raw = await self.ws_server.recv()

    # process by multiple clients parallely:
    await asyncio.gather(
        self.process_by_client_1(request_raw),
        self.process_by_client_2(request_raw),
        self.process_by_client_3(request_raw),
    )

我不确定我是否理解正确,但多个协同程序不是你想要的吗

while True:
    request_raw = await self.ws_server.recv()

    # process by multiple clients parallely:
    await asyncio.gather(
        self.process_by_client_1(request_raw),
        self.process_by_client_2(request_raw),
        self.process_by_client_3(request_raw),
    )

下面是一个非常简单的发布/订阅websockets服务器示例

import asyncio
import websockets

connections = set()
n = 0


async def handler(websocket, path):
    global n

    if path == "/sub":
        n = n + 1
        i = n
        connections.add(websocket)
        print("adding subscriber #", i)
        try:
            async for msg in websocket:
                pass  # ignore
        except websockets.ConnectionClosed:
            pass
        finally:
            print("removing subscriber #", i)
            connections.remove(websocket)

    elif path == "/pub":
        async for msg in websocket:
            print("<", msg)
            for ws in connections:
                asyncio.ensure_future(ws.send(msg))


start_server = websockets.serve(handler, 'localhost', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

下面是一个非常简单的发布/订阅websockets服务器示例

import asyncio
import websockets

connections = set()
n = 0


async def handler(websocket, path):
    global n

    if path == "/sub":
        n = n + 1
        i = n
        connections.add(websocket)
        print("adding subscriber #", i)
        try:
            async for msg in websocket:
                pass  # ignore
        except websockets.ConnectionClosed:
            pass
        finally:
            print("removing subscriber #", i)
            connections.remove(websocket)

    elif path == "/pub":
        async for msg in websocket:
            print("<", msg)
            for ws in connections:
                asyncio.ensure_future(ws.send(msg))


start_server = websockets.serve(handler, 'localhost', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

换句话说,我需要与多个使用者在同一个循环和线程中运行
.recv
。在RxPy中,我可以
stream.emit(recv\u result)
并使用类似
thatstrem.subscribe(callback\u fn)
的项目,但这是回调方式,我需要异步

您的
subscribe
方法可以接受协同路由函数,即使用
async def
创建的函数。一旦有东西发出,就可以使用
create\u task
实例化它们并生成它们的协同程序:

def __init__(self, ...):
    self._subscribers = []

def subsribe(self, corofn):
    self._subscribers.append(corofn)

def emit(self, obj):
    loop = asyncio.get_event_loop()
    for corofn in self._subscribers:
        coro = corofn(obj)
        loop.create_task(coro)

async def main(self):
    while True:
        request_raw = await self.ws_server.recv()
        self.emit(request_raw)

换句话说,我需要与多个使用者在同一个循环和线程中运行
.recv
。在RxPy中,我可以
stream.emit(recv\u result)
并使用类似
thatstrem.subscribe(callback\u fn)
的项目,但这是回调方式,我需要异步

您的
subscribe
方法可以接受协同路由函数,即使用
async def
创建的函数。一旦有东西发出,就可以使用
create\u task
实例化它们并生成它们的协同程序:

def __init__(self, ...):
    self._subscribers = []

def subsribe(self, corofn):
    self._subscribers.append(corofn)

def emit(self, obj):
    loop = asyncio.get_event_loop()
    for corofn in self._subscribers:
        coro = corofn(obj)
        loop.create_task(coro)

async def main(self):
    while True:
        request_raw = await self.ws_server.recv()
        self.emit(request_raw)

谢谢你的建议,它们可能有用。我排起队来了

class SWebsocket(object):

    def __init__(self, websocket: WebSocketServerProtocol):
        self.ws = websocket
        self.queues = {}
        self.subscribe()

    def subscribe(self):
        # fire and forget function
        asyncio.ensure_future(self.recv_mess())

    async def recv_mess(self):
        while True:
            try:
                data = await self.ws.recv()
            except websockets.ConnectionClosed as e:
                for _, q in self.queues.items():
                    await q.put(e)
                return
            for _, q in self.queues.items():
                await q.put(data)

    async def recv(self, id):
        # read value from queue
        if id not in self.queues:
            self.queues[id] = asyncio.Queue()
        data = await self.queues[id].get()
        if isinstance(data, websockets.ConnectionClosed):
            raise data
        return data

谢谢你的建议,它们可能有用。我排起队来了

class SWebsocket(object):

    def __init__(self, websocket: WebSocketServerProtocol):
        self.ws = websocket
        self.queues = {}
        self.subscribe()

    def subscribe(self):
        # fire and forget function
        asyncio.ensure_future(self.recv_mess())

    async def recv_mess(self):
        while True:
            try:
                data = await self.ws.recv()
            except websockets.ConnectionClosed as e:
                for _, q in self.queues.items():
                    await q.put(e)
                return
            for _, q in self.queues.items():
                await q.put(data)

    async def recv(self, id):
        # read value from queue
        if id not in self.queues:
            self.queues[id] = asyncio.Queue()
        data = await self.queues[id].get()
        if isinstance(data, websockets.ConnectionClosed):
            raise data
        return data

你能发布一个
最简单的例子吗?所以我可以试试你的代码吗?这将是一个相当大的例子,你可能需要将问题抽象到你正在努力解决的特定部分。如果它是非常特定于领域的,其他人将无法理解代码的意图。这可能是一个挑战……你能发布一个
最简单的例子吗?所以我可以试试你的代码吗?这将是一个相当大的例子,你可能需要将问题抽象到你正在努力解决的特定部分。如果它是非常特定于领域的,其他人将无法理解代码的意图。这可能是一个挑战…是的,我想要这样的东西,但我需要动态地添加
process\u by\u client\u
。(如添加回调,但我需要使用
wait
关键字运行它。换句话说,我需要在同一个循环和线程中与多个使用者一起运行
.recv
。在RxPy中,我可以只
stream.emit(recv_result)
并使用类似于
strem.subscribe(callback\fn)的项)
,但这是回调方式,我需要异步是的,我想要类似的东西,但我需要动态添加
process\u by\u client\u
。(比如添加回调,但我需要使用
wait
关键字运行它。换句话说,我需要在同一个循环和线程中与多个使用者一起运行
.recv
。在RxPy中,我可以只
stream.emit(recv_result)
并使用类似
strem.subscribe(callback\fn)
,但这是回调方式,我需要异步。)