目前,我正在开发一个IoT Mockup Client,它可以读取几个真实的时间序列数据CSV,并根据其时间戳和系统时钟(threading
模块)“重放”它们。
所以基本上我有一个Pandas数据框,其中保存了所有旧数据,还有一个计时器滴答处理程序函数,该函数从中提取相应的行以将其输出到任何数据接收器。
如果我的计时器处理程序使用requests.post(..
然后仅发布从df[...<current-timeslice-filer>...].to_csv()
收集的文本正文,则此方法非常有效。
现在,我想将此数据流传输到服务器api,因此我们决定通过Websockets而不是HTTP-REST传输数据。事情开始变得棘手。 websockets
模块高度依赖asyncio
,它需要自己的事件循环。因为我的计时器已经是一个事件循环(基于threading.timer
),并且我必须承认我不完全了解asyncio的概念,所以我认为这不太适合。
至少我不知道如何将websocket.send()方法集成到我的处理程序方法中,以便使其在asyncio事件循环内运行。
DataFrame.to_csv(...可以被赋予文件处理程序file_or_buf
,我将不胜感激,像文件处理程序一样使用websocket并在此处提供它,以刷新我的数据。>
websockets
模块来实现这一目标吗?我只是看错了吗?编辑到目前为止的内容...
那是我的计时器类,每do()
秒调用一次方法interval
from threading import Thread,Event
class TimeTicker(Thread):
def __init__(self, interval=1):
Thread.__init__(self)
self.interval = interval
self.stopped = Event()
def run(self):
while not self.stopped.wait(self.interval):
self.do()
def do(self):
print('tick')
def get_stopflag(self):
return self.stopped
现在,使用websockets
和asyncio
的基本代码是...
import asyncio
import websockets
async def hello():
uri = "ws://echo.websocket.org"
async with websockets.connect(uri) as websocket:
await websocket.send(thread.stream())
r = await websocket.recv()
print(r)
asyncio.get_event_loop().run_until_complete(hello())
我已经尝试过创建do()
方法async
,但是我无法在asyncio事件循环内初始化TimeTicker
类,因此“等待”方法调用>
为使情况更清楚,我想在TimeTicker对象外部初始化websocket连接(它仅应每秒提供时间序列数据并将其传递给websocket.send()
。尽管如此,我不确定该数据传递应该在哪里这样的话,也许还有更好的TimeTicker类解决方案来每秒yield
数据,而不仅仅是调用方法。总之,我想就此寻求建议。
提示:TimeTicker只是我的数据源类的一个超类,它实际上保存着大约为pandas的数据帧。从CSV读取20万行时间序列数据作为要发送的存储库。
解决方案:基于@ wowkin2的答案,现在我的TimeTicker类仅通过asyncio即可实现...
import asyncio
import websockets
class TimeTicker:
is_stopped = False
def __new__(cls, _loop, _uri, interval=1):
instance = super().__new__(cls)
instance.interval = interval
instance.uri = _uri
instance.task = _loop.create_task(instance.run())
return instance.task
async def run(self):
async with websockets.connect(self.uri) as self.ws:
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"
loop = asyncio.get_event_loop()
task = TimeTicker(loop, uri, interval=5)
loop.run_until_complete(task)
答案 0 :(得分:1)
如果使用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)