[英]Process async results in another thread - app architecture (python-3.7)
我有一個程序從 Binance API 接收數據(交易)。 這些數據將在帶有破折號和 plotly 的網絡應用程序中進行處理和可視化。
為了獲得最佳性能和最小延遲,我的程序有 3 個線程:
線程 1 - 幣安 API - 獲取請求 - 交易
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
binance-thread = threading.Thread(target=start_thread_1)
...
def start_thread_1():
loop.run_until_complete(main(api_key,secret_key))
async def main(api_key,secret_key):
client = await AsyncClient.create(api_key,secret_key)
await trades_listener(client)
async def trades_listener(client):
bm = BinanceSocketManager(client)
symbol = 'BTCUSDT'
async with bm.trade_socket(symbol=symbol) as stream:
while True:
msg = await stream.recv()
event_type = msg['e']
...
trade = Trade(event_type,...)
# <-- safe trade SOMEWHERE to process in other thread ? safe to: process_trades_list
線程 2 - Web 應用程序 - 顯示交易和已處理的交易數據
web-thread = threading.Thread(target=webserver.run_server)
...
not worth to mention
線程 3 - 處理數據 - 處理交易(計算 RSI、過濾大宗交易等)
if __name__ == "__main__":
try:
loop = asyncio.get_event_loop()
binance-thread = threading.Thread(target=start_thread_1)
web-thread = threading.Thread(target=webserver.run_server)
process-thread = threading.Thread(target=start_thread_3)
...
.start()
.sleep()
etc.
.join()
def start_thread_3():
process_trades()
def process_trades():
global process_trades_list
while True:
while len(process_trades_list) > 0:
trade = process_trades_list[0]
process_trades_list.pop(0)
# ...do calculation etc.
如何安全/將數據從 thread_1/異步線程移交給 thread_3? 我試圖將交易放到一個名為process_trades_list
的列表中,然后while len(process_trades_list) > 0
all trades 時循環。 在循環中,我pop()
處理了列表中的交易——但這似乎在不引發錯誤的情況下破壞了程序。 完成這項工作的最佳方法是什么?
異步 stream 可能會被新的傳入交易發送垃圾郵件,我想最小化負載..
在這里,您需要一個 queue.Queue 而不是列表。 您的最后一個代碼段看起來像這樣:
import queue
if __name__ == "__main__":
try:
q = queue.Queue()
binance_thread = threading.Thread(target=start_thread_1,
args=(q,))
web_thread = threading.Thread(target=webserver.run_server)
process)thread = threading.Thread(target=process_trades,
args=(q,), daemon=True)
...
.start()
.sleep()
etc.
.join()
def process_trades(q):
while True:
trade = q.get()
# ...do calculation etc.
我消除了對 get_event_loop 的調用,因為您沒有使用返回的 object。 我去掉了start_thread_3 function,這不是必須的。
我將 thread-3 設置為守護進程,因此如果其他一切都完成,它不會讓您的應用程序保持打開狀態。
隊列應該在主線程中創建一次,並顯式傳遞給需要訪問它的每個線程。 這消除了對全局變量的需要。
加工貿易function變得簡單多了。 q.get() 調用會阻塞,直到 object 可用。 它還將 object 從隊列中彈出。
接下來,您還必須修改 thread-1 以將對象放入隊列中,如下所示:
def start_thread_1(q):
asyncio.run(main(api_key,secret_key, q))
async def main(api_key,secret_key, q):
client = await AsyncClient.create(api_key,secret_key)
await trades_listener(client, q)
async def trades_listener(client, q):
bm = BinanceSocketManager(client)
symbol = 'BTCUSDT'
async with bm.trade_socket(symbol=symbol) as stream:
while True:
msg = await stream.recv()
event_type = msg['e']
...
trade = Trade(event_type,...)
q.put(trade)
q.put function 是您如何安全地將交易 object 放入隊列中的方法,這將導致線程 3 中的活動。
我修改了start_thread1 function:這里是為這個線程啟動事件循環機制的好地方。
您詢問如何避免對您的程序進行垃圾郵件攻擊。 隊列具有允許您限制其大小的方法,並且如果它們已滿,則可能會丟棄交易。
我不明白你想用線程 1 中的if __name__ == '__main__'
邏輯做什么。 該程序只能有一個入口點,並且只有一個名為'__main__'
。 在我看來,這必須是線程 3。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.