[問題] thread 吃光 CPU 效率,想自行控制

作者: HuangJC (吹笛牧童)   2023-01-29 20:31:15
最近在做一個專案,裡面有三十個設備要控制
因為三十個設備不能互相卡住,所以就開了三十個 thread
另外程式要有所展示,所以 main thread 也就是 ui thread
由 main thread 開出 30 個設備 thread, 那現在看到有 31 個了
CPU 的效率撥進來這支程式,假設是平均且 free run
那麼每個 thread 都佔用了 1/31 的 CPU 時間
我在每個 thread 做過一次判斷後,都有 sleep(1)
這意思是每個設備,每秒都判斷一次應該要做什麼動作
這時 UI 變很卡了...
理想上每個 thread 遇到 sleep 指令,它就睡了
然後 CPU 時間會撥給剩下的 thread 去平均分享
如果每個設備的判斷式都執行很快,那麼在別的 thread 的 sleep 一秒內,就足以做完
當程式跑久以後,每個 thread 都有可能全速奔馳
只要它們別同時醒著
也許是我寫的判斷式效率不好,漸漸的感覺到程式變很卡
而把 sleep 加長有助於解決這個問題
其實我想分配每個 thread 的優先權了
一開始的想法便是利用 lock
首先產生一個 lock 當全域物件
30 個 thread 都引用它且互斥
with lock:
設備判斷式
這樣可使 30 個 thread 同時只能有一個執行
而我在設備判斷式裡,也只簡單的把一個計數器加一
據以觀察 30 個設備的執行機率平不平均
結果是非常不平均;但這樣寫是最簡單的
我會擔心,會不會運氣不好,某設備經常不執行?
後來我想了一個法子,由我自己控制
我產生一個 list, 裡面有所有 30 個設備 thread 的指標
只要某 thread 被執行,就把它移到 list 的最尾端
那麼最前端就是沒被執行到,我希望它執行的
用這個方法等於把 30 個 thread 串起來,因為同時只有一個在動
我等於就把它們變一個 thread (難道 thread group 就是在做這件事?)
我希望的是 30個設備 thread 總共佔用 50% CPU 時間
而 main thread 佔用另外的 50% CPU 時間;也就是平分~
這樣會不會有什麼問題呢?有沒有更簡單的想法呢?
覺得自己打造了不少輪子
而且這樣似乎又違反了一開始的初衷(設備不要互相卡住)
因為我只要一個設備有 bug, 卡住不動
剩下 29 個設備會全部賠葬 XD
把話反過來說好了,一開始我就不想寫 30 個 thread,我本來要用一個 thread 做完
舉例來說,一個射擊類電玩裡,敵機可能有一百架
難道這電玩就用一百個 thread 來寫?
當然是一個 thread 就很好寫啊...
但因為我的開發出了點問題,老闆就叫我快點改成 multi-thread
至少一個設備卡住也不影響其他設備
另外當初在學同步物件時,有個東西就搞不懂
好像有個叫 信號機 的物件,它不像 lock 是完全互斥
而是它可以允許一個量(比如同時有五個 thread pass,一個結束才能再喚醒一個)
我一直無法想像這東西用在哪,從沒用過
難道就用在這?
比如,我 30 個設備會卡,但當初開發到一半時還很順,大概可以容許 15 個設備
我就設 15 個設備的信號機,這樣程式也不會卡,但也不是同時所有 thread 都在動
難道就是用在這?
但我還是會擔心,允許 15 個設備,就有哪個設備不受照顧,睡死一方..
這種同步物件,有保證所有 thread 的機率儘量均等嗎?
以上請教,謝謝
作者: surimodo (好吃棉花糖)   2023-01-29 23:13:00
叫老闆升級CPU
作者: poototo (poototo)   2023-01-29 23:18:00
GIL下,thread本來就是互斥的客製互斥鎖沒有改變thread互斥性,只會影響公平性可試試Coroutines&Tasks,管理成本比thread低很多
作者: TakiDog (多奇狗)   2023-01-30 01:49:00
當今天出現sleep 應該要思考流程設計asyncio.sleep 會更好的去釋放資源你大可一個設備一個process溝通,資料再彙整到一處
作者: timsheu (為道日損)   2023-01-30 09:29:00
asyncio效能比multi-thread好很多,但語法要熟悉一下multi-process的話,若資料要互通要用share memory官方的asyncio用不習慣的話,也可以用trio,比較容易上手asyncio要注意一下python版本,有些語法只適用python3.8+我是用rpi4b架fastapi,python3.7,asyncio+rxpyasyncio要同時跑coroutine的話,要包成task才行。
作者: day831231 (下個地點)   2023-01-31 06:32:00
假設只有一個CPU那用thread 跟 process 速度不會差到太多感覺只是使用方式錯誤
作者: Falldog (Yo)   2023-01-31 23:19:00
GIL卡的是python layer, C level的不會卡, eg. socket io理論上ui會感到卡一定是main thread做太多事卡住render用thread的話,就盡量用event queue的方式溝通如果在main thread需要跟其他thread用lock搶資源的話會卡似乎也是預期內的事補充一下 GIL, C level 有機會可以 release GIL
作者: poototo (poototo)   2023-02-01 00:52:00
PEP 703就有可能讓GIL Optional
作者: zerof (貓橘毛發呆雕像)   2023-02-01 16:38:00
左轉 pypy
作者: s9041200 (小明阿)   2023-02-01 20:10:00
試過epoll嗎?
作者: eight0 (欸XD)   2023-02-04 00:17:00
https://github.com/eight04/pyWorker 不知道有沒有幫助

Links booklink

Contact Us: admin [ a t ] ucptt.com