簡體   English   中英

在另一個線程中處理異步結果 - 應用程序架構(python-3.7)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM