作者HuangJC (吹笛牧童)
看板Python
標題Re: [問題] 請問 Coroutine & 一般 callback 合作的問題
時間Mon Feb 6 12:28:21 2023
※ 引述《TakiDog (多奇狗)》之銘言:
: 如果程式中出現threading(非Asyncio.run_in_executor)與Async混用
: 我一定會先思考人生,是不是把Python變難了,是不是能從流程改善
: 讓被歧視的膠水語言保有最後一點的優雅
一開始我就說,全用 thread 和 全用 Coroutine 我都做得到
但我有非得混用的理由,原因是我用了從網路下載的模組
它有它的 callback, 而 callback 不是我寫的,其宣告不帶有 async
至於流程 work around 我也做到了,但感覺像 polling
問題在這裡不好
: > https://paste.ee/p/kgAsv
: 在同一個process中任意執行 asyncio.run 並不一定是同一個eventLoop
: (不同thread又分別建立了Loop)
這我是知道的
: 在整個process中 asyncio.run 基本上只應該存在一個
我以為,不同 thread 可以各別有 asyncio.run
: 你可以嘗試把asyncio.run的部分都改用 loop = get_event_loop()
: 查看loop的id. 或從Debugger查看
: ---
: 我嘗試在你最後的code中修改,在同一個process存在2個loop
: 又希望不同的loop之間可以通知,感覺上就不太正確。
就是要想法子只有一個 loop
在 thread1 中把 loop 取出來
在 thread2 中,利用這個 loop 想要通知它
我也試過這種
其實一開始因為我沒找到貼 code 的方法,我試圖只用文字說明,我以為這可以
因為其實邏輯概念是跨語言的
multi-thread 在 C 有,在 python 也有;雖然不一樣,但不影響這個例子
Coroutine 在 C 我沒用過,但我相信也有實踐其概念的方法
所以我說明了一下,然後得到我必需重讀 OS 的評語
我不介意重讀,因為總是輸人一步
但我介意的是時間的分配,我可能必需趕快學別的東西,而不是成為 OS 專家。。
或者有人為了和我談 python 的 multi-thread 不是真的這件事
而把話題扯遠了(那豈不是專注在我文章中的任何漏洞,而不在文章的總體概念?)
: :https://gist.github.com/takidog/c53f73e24295d66c76b5e330940bcf73
: 可以把loop, condition當作arg傳入,或是當作global
: (我認為都非常的糟糕)
只要能解,都可能比我原本的解法好
本來 loop 是在高階 Coroutine 不用見到的東西
但碰到 bug 可能就要從低階去解
: > 因為有某些部份是引用別人寫的 lib, 我不想去全面改寫
: :run_in_executor
: 我的理解可能也有錯誤,歡迎討論
附上程式
可以更好的形容為什麼我用了別人的東西,
而別人沒 async 的 callback 我為何不能改寫
https://paste.ee/p/Jvrxb
框架是這樣,註解在程式裡
本來不想列成這樣是因為還要麻煩板友安裝 guizero
一堆人都在用 PyQt,可能會覺得這個冷門
所以我就想:反正就是要交代我得有 non async callback;用說的就好
但看來只會被人說把問題變複雜了
問題是本來就複雜的,除非我去改寫 guizero
或許我真有本事改寫,畢竟它也附上 source code
但與其自己維護它,我傾向於不改它
題目就是 怎麼在 non async callback 中和已經存在的 Coroutine 互動
也有板友提及 epoll, 那我就不知 epoll 有沒有提供 async callback 了
或者得自己面對這個問題;那問題還是會回到同一點上
※ 編輯: HuangJC (123.204.157.162 臺灣), 02/06/2023 13:17:45
1F:→ zerof: GUI 的設計原本就是 event-based, 一定會有 callbacks ;你 02/06 13:32
2F:→ zerof: 的問題多到我不知道該從何吐槽,最原始的問題你其實可以左 02/06 13:32
3F:→ zerof: 轉 cython 學一下 release GIL 的用法就不會卡到 GUI (guiz 02/06 13:32
4F:→ zerof: ero 底層是用 tk, written in C) 02/06 13:32
我也可以用 multi-process 而不是 thread 來解啊
解法不只一種,而且我不認為問題出在 GIL
畢竟我的 thread 有三十多個,我也真嫌多了
用了 Coroutine 就合併回一個,但卻是三十多個 task
我覺得這也蠻好的
Coroutine 既然是個潮流就來了解一下,有別的解法就先放一邊吧..
真要 C 我何不回 C 的世界,寫純 C..
5F:推 surimodo: 你python版本用多少 02/06 13:36
3.7, 前一篇有人回我 asyncio.to_thread 這應該是個解,但要 3.9
而它的底層我猜就是 loop.run_in_executo,這應該是同一回事
我目前正在了解 takidog 的邏輯,他那程式是跑起來了
我看能不能擺進 guizero 的 callback 框架裡
await asyncio.gather(job1, job2)
這句可能會出問題,因為真的把 guizero 的例子附上後
我不知要在哪裡 gather 它。。。
我非得拆散他們不可? XD
6F:→ lycantrope: to_thread就是run_in_executor 02/06 14:26
https://paste.ee/p/HzTH3
這是較為完整的例子
包含了程式的退出(之前只為了測試某些目的,程式有 bug 無法結束都不管)
結果我還是只能用 polling 寫出來
因為我無法把該 gather 在一起的東西拆開!
至於全域變數的使用,傳送。。。
暴力點,用 class 就好 XD
我也試過把整個 main 宣告為 async,讓它當我 Coroutine 的根部
但是失敗了
※ 編輯: HuangJC (123.204.157.162 臺灣), 02/06/2023 16:13:45
8F:→ poototo: 以上連結是使用兩種condition 02/06 23:32
9F:→ poototo: asyncio.condition是基於asyncio.event 02/06 23:33
10F:→ poototo: asynio.notify跨緒僅可解鎖及廣播同eventloop的waiter 02/06 23:36
11F:推 poototo: loop向下對task,向上對thread,越級對其他loop的task 02/06 23:53
12F:→ poototo: 我不確定可行性,但異步管理弄太複雜我寧願犧牲效能... 02/06 23:55
我就是這樣做,但你這個例子也無法搬至 guizero 上
我前面有想搬 TakiDog 的例子,但發現無法找到 gather 的點
搬至 guizero 後我是要做到 UI 互動
也就是 task 1 要是個 loop 不斷跑
而 sync func 是由螢幕上的按鍵經使用者互動,guizero 會 callback
每 callback 一次,task 1 的 loop 就解鎖 condition 跑一次 do 1, do2, .....
你的例子,t_cond 不在 task1a 裡,所以 task1a 不是早就執行起來等
也不會是每經 t_cond callback 一次,task1a 就繞一次
稍微改一下就是我後來的解法了
14F:推 OnoderaHaru: 反正最後還是包裝成執行緒,直接用執行緒可以用的來 02/07 01:04
15F:→ OnoderaHaru: 溝通 02/07 01:04
https://paste.ee/p/OxGNI
這會有問題
我把 reportTask 再進一步弄成 reportTask1, reportTask2
其中 reportTask2 就是無腦一直 looping
運作良好
然後把 self.q.get() 那行 unmark 就會發現問題
threading 的 queue (或任何同步物件)
它是阻塞一整個 queue
因為所有的 task 事實上是同一個 thread,所以一個塞住其他就塞住了
這就是要改用 asyny 版本的 queue 的原因
任何的阻塞,不管是 condition, lock, sleep
只要是 async 版本的,就能把執行權轉移到其他 task 上去
這樣使用 Coroutine 的 task 才有意義
其實我在前面的討論裡都有提及這些,只是文筆不好,無法讓大家理解這個意思
但現在這篇應該能解釋了(我回去修文改成紅色的部份)
這個可以 XD
那我就是想法子利用這個 queue 去湊架構了...
剛草草看了底層 source code
不很清楚它怎麼做到 sync async 轉換的
----
這一面貼兩個程式我不會,是不是因為我沒註冊 XD
※ 編輯: HuangJC (1.168.18.180 臺灣), 02/08/2023 13:38:59
※ 編輯: HuangJC (116.241.233.114 臺灣), 03/04/2023 03:36:10