亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

用于遷移現有代碼庫的線程中的 Python asyncio

用于遷移現有代碼庫的線程中的 Python asyncio

偶然的你 2023-05-09 15:36:55
我們有一個相當大的項目,它正在做大量的網絡(API 調用、Websocket 消息),并且還有很多內部作業在線程中間隔運行。我們當前的架構涉及生成大量線程,當系統負載很大時,應用程序無法正常運行,因此我們決定嘗試使用 asyncio。我知道最好的方法是將整個代碼庫遷移到異步代碼,但由于代碼庫的大小和有限的開發資源,這在不久的將來是不現實的。但是,我們希望開始遷移部分代碼庫以使用 asyncio 事件循環,并希望我們能夠在某個時候轉換整個項目。到目前為止我們遇到的問題是整個代碼庫都有同步代碼,為了在里面添加非阻塞異步代碼,代碼需要在不同的線程中運行,因為你不能真正在同一個線程中運行異步和同步代碼線。為了結合異步和同步代碼,我想出了這種在應用程序啟動時創建的單獨線程中運行異步代碼的方法。代碼的其他部分只需調用 add_asyncio_task 即可將作業添加到此循環中。import threadingimport asyncio_tasks = []def threaded_loop(loop):    asyncio.set_event_loop(loop)    global _tasks    while True:        if len(_tasks) > 0:            # create a copy of needed tasks            needed_tasks = _tasks.copy()            # flush current tasks so that next tasks can be easily added            _tasks = []            # run tasks            task_group = asyncio.gather(*needed_tasks)            loop.run_until_complete(task_group)def add_asyncio_task(task):    _tasks.append(task)def start_asyncio_loop():    loop = asyncio.get_event_loop()    t = threading.Thread(target=threaded_loop, args=(loop,))    t.start()在 app.py 的某處:start_asyncio_loop()以及代碼中的其他任何地方:add_asyncio_task(some_coroutine)由于我是 asyncio 的新手,我想知道在我們的情況下這是否是一種好方法,或者這種方法是否被認為是一種反模式并且有一些問題會在以后的道路上打擊我們?或者也許 asyncio 已經有了一些解決方案,而我只是想在這里發明輪子?感謝您的投入!
查看完整描述

1 回答

?
慕后森

TA貢獻1802條經驗 獲得超5個贊

這種方法總體上很好。你有一些問題:

(1)幾乎所有的asyncio對象都不是線程安全的

(2) 您的代碼本身不是線程安全的。如果任務出現在之后needed_tasks = _tasks.copy()但之前怎么辦_tasks = []?這里需要一把鎖。順便說一句,復制是沒有意義的。簡單needed_tasks = _tasks就行了。

(3) 一些 asyncio 結構是線程安全的。使用它們:

import threading

import asyncio


# asyncio.get_event_loop() creates a new loop per thread. Keep

# a single reference to the main loop. You can even try

#? ?_loop = asyncio.new_event_loop()

_loop = asyncio.get_event_loop()


def get_app_loop():

? ? return _loop


def asyncio_thread():

? ? loop = get_app_loop()

? ? asyncio.set_event_loop(loop)

? ? loop.run_forever()


def add_asyncio_task(task):

? ? asyncio.run_coroutine_threadsafe(task, get_app_loop())


def start_asyncio_loop():

? ? t = threading.Thread(target=asyncio_thread)

? ? t.start()


查看完整回答
反對 回復 2023-05-09
  • 1 回答
  • 0 關注
  • 118 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號