通过python websocket重放基于计时器的数据

通过python websocket重放基于计时器的数据,python,websocket,python-asyncio,Python,Websocket,Python Asyncio,目前,我正在开发一个IoT模拟客户端,该客户端读取两个真实世界的timeseries数据CSV,并根据它们的时间戳和系统时钟(“代码>线程化”模块)“重放”它们 所以基本上我有一个Pandas数据框,它保存所有旧数据,还有一个timer tick handler函数,它从中提取相应的行,将它们提供给任何数据接收器 如果我的计时器勾号处理程序使用requests.post(..然后只将从df[..]收集的文本正文发布到\u csv(),则此功能非常有效 现在我想将这些数据流式传输到服务器api,因

目前,我正在开发一个IoT模拟客户端,该客户端读取两个真实世界的timeseries数据CSV,并根据它们的时间戳和系统时钟(“代码>线程化”模块)“重放”它们

所以基本上我有一个Pandas数据框,它保存所有旧数据,还有一个timer tick handler函数,它从中提取相应的行,将它们提供给任何数据接收器

如果我的计时器勾号处理程序使用
requests.post(..
然后只将从
df[..]收集的文本正文发布到\u csv()
,则此功能非常有效

现在我想将这些数据流式传输到服务器api,因此我们决定通过WebSocket而不是HTTP-REST传输数据。事情开始变得棘手。模块严重依赖于
asyncio
,它需要自己的事件循环。因为我的计时器已经是一种事件循环(基于
threading.timer
)我必须承认,我并不完全理解asyncio的概念,我认为这并不完全适合

至少我不知道如何将websocket.send()方法集成到我的处理程序方法中,以便它在asyncio事件循环中运行

DataFrame.to_csv(…可以提供一个文件处理程序
file_或_buf
,我更希望像文件处理程序一样使用websocket,并在此处提供它,以刷新我的数据

  • python中是否有另一个websocket实现使用了这种范例
  • 可以使用
    websockets
    模块来实现这一点吗?我只是弄错了吗
  • 我是否也必须使用asyncio实现基于时间间隔的数据发送处理程序,以便两者都在事件循环中运行
编辑我到目前为止的内容

这是我的计时器类,它每隔
间隔
秒调用方法
do()

从线程导入线程,事件
类计时器(线程):
定义初始值(自,间隔=1):
线程。\uuuu初始化\uuuuu(自)
self.interval=间隔
self.stopped=Event()
def运行(自):
而不是自停。等待(自停。间隔):
self.do()
def do(自我):
打印('勾选')
def get_停止标志(自身):
自动停止返回
现在使用
websockets
asyncio
的基本代码片段是

导入异步IO
导入WebSocket
异步def hello():
uri=“ws://echo.websocket.org”
与websocket异步。作为websocket连接(uri):
等待websocket.send(thread.stream())
r=等待websocket.recv()
印刷品(r)
asyncio.get_event_loop()。运行_直到完成(hello())
我已经尝试使我的
do()
method
async
,但我无法在asyncio事件循环中初始化我的
TimeTicker
类,因此方法调用被“等待”

为了清楚起见,我想在TimeTicker对象外部初始化websocket连接(它应该每秒只提供timeseries数据,并将其传递给
websocket.send()
。然而,我不确定这一数据传递应该发生在哪里。我的TimeTicker类也可能有更好的解决方案,
每秒产生
数据,而不仅仅是调用一个方法。无论如何,我希望得到这方面的建议

提示:TimeTicker只是我的datasource类上的一个超类,它实际上包含pandas数据帧,其中包含从CSV读取的大约200.000行timeseries数据,作为要发送的存储库

解决方案:基于@wowkin2的答案我的TimeTicker类现在仅用asyncio实现了

导入异步IO
导入WebSocket
班级计时器:
is_stopped=False
定义新(cls,循环,uri,间隔=1):
instance=super()。\uuuuu new\uuuuu(cls)
instance.interval=interval
instance.uri=\u uri
instance.task=\u loop.create\u任务(instance.run())
return instance.task
异步def运行(自):
与websockets.connect(self.uri)作为self.ws异步:
尽管如此:
等待自我
等待异步睡眠(self.interval)
异步def do(自):
消息='ping'
等待self.ws.send(消息)
r=wait self.ws.recv()
印刷品(r)
def停止(自):
self.task.cancel()
self.is_stopped=True
uri=“ws://echo.websocket.org”
loop=asyncio.get\u event\u loop()
任务=计时器(循环,uri,间隔=5)
循环。运行_直到_完成(任务)

如果使用asyncio,则不需要线程模块

下面是一个如何使用asyncio定期执行某些操作的示例。 唯一的一件事——您需要有一个始终打开连接的变量,而不需要上下文管理器

import asyncio


class TimeTicker:
    is_stopped = False

    def __new__(cls, _loop, _ws, interval=1):
        instance = super().__new__(cls)
        instance.interval = interval
        instance.ws = _ws
        instance.task = _loop.create_task(instance.run())
        return instance.task

    async def run(self):
        while True:
            await self.do()
            await asyncio.sleep(self.interval)

    async def do(self):
        message = 'ping'
        await self.ws.send(message)
        r = await self.ws.recv()
        print(r)

    def stop(self):
        self.task.cancel()
        self.is_stopped = True


uri = "ws://echo.websocket.org"
ws = websockets.connect(uri)

loop = asyncio.get_event_loop()
task = TimeTicker(loop, ws, interval=5)
loop.run_until_complete(task)


每一秒我们都会得到数据(从哪里来?)然后将其发送到web套接字?是
TimeTicker。是否
获取我们需要通过web套接字发送的数据?否,因为这样它每次都会创建到websocket的新连接…我已经尝试连接外部并将连接传递到函数,但这不在循环的范围内,而且“未等待”@Hadus是的,然后通过self.dataframe在对象中可用。如果不使用线程在调用之前等待,则会更容易。您也可以在异步事件循环中等待。例如,在收到web套接字的响应后,您可以计算在再次联系web套接字之前需要等待的时间。这样,您可以我们将使用相同的连接。必须稍微采用它添加
与websockets.connect(self.uri)异步作为self.ws:
之前的一行,而为True
这样websocket连接就被初始化了。IDK为什么,但是通过构造函数传递
ws
处理程序是不起作用的。整洁的类构造函数模式顺便说一句,我不知道。这对我现在运行我的东西有很大帮助!非常感谢!