Re: [問題] 請問 Coroutine & 一般 callback 合作的問題
※ 引述《TakiDog (多奇狗)》之銘言:
: 如果程式中出現threading(非Asyncio.run_in_executor)與Async混用
: 我一定會先思考人生,是不是把Python變難了,是不是能從流程改善
: 讓被歧視的膠水語言保有最後一點的優雅
一開始我就說,全用 thread 和 全用 Coroutine 我都做得到
但我有非得混用的理由,原因是我用了從網路下載的模組
它有它的 call back, 而 call back 不是我寫的,其宣告不帶有 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 call back;用說的就好
但看來只會被人說把問題變複雜了
問題是本來就複雜的,除非我去改寫 guizero
或許我真有本事改寫,畢竟它也附上 source code
但與其自己維護它,我傾向於不改它
題目就是 怎麼在 non async callback 中和已經存在的 Coroutine 互動
也有板友提及 epoll, 那我就不知 epoll 有沒有提供 async call back 了
或者得自己面對這個問題;那問題還是會回到同一點上
※ 編輯: HuangJC (123.204.157.162 臺灣), 02/06/2023 13:17:45
→
02/06 13:32,
1年前
, 1F
02/06 13:32, 1F
→
02/06 13:32,
1年前
, 2F
02/06 13:32, 2F
→
02/06 13:32,
1年前
, 3F
02/06 13:32, 3F
→
02/06 13:32,
1年前
, 4F
02/06 13:32, 4F
我也可以用 multi-process 而不是 thread 來解啊
解法不只一種,而且我不認為問題出在 GIL
畢竟我的 thread 有三十多個,我也真嫌多了
用了 Coroutine 就合併回一個,但卻是三十多個 task
我覺得這也蠻好的
Coroutine 既然是個潮流就來了解一下,有別的解法就先放一邊吧..
真要 C 我何不回 C 的世界,寫純 C..
推
02/06 13:36,
1年前
, 5F
02/06 13:36, 5F
3.7, 前一篇有人回我 asyncio.to_thread 這應該是個解,但要 3.9
而它的底層我猜就是 loop.run_in_executo,這應該是同一回事
我目前正在了解 takidog 的邏輯,他那程式是跑起來了
我看能不能擺進 guizero 的 call back 框架裡
await asyncio.gather(job1, job2)
這句可能會出問題,因為真的把 guizero 的例子附上後
我不知要在哪裡 gather 它。。。
我非得拆散他們不可? XD
→
02/06 14:26,
1年前
, 6F
02/06 14:26, 6F
https://paste.ee/p/HzTH3
這是較為完整的例子
包含了程式的退出(之前只為了測試某些目的,程式有 bug 無法結束都不管)
結果我還是只能用 polling 寫出來
因為我無法把該 gather 在一起的東西拆開!
至於全域變數的使用,傳送。。。
暴力點,用 class 就好 XD
我也試過把整個 main 宣告為 async,讓它當我 Coroutine 的根部
但是失敗了
※ 編輯: HuangJC (123.204.157.162 臺灣), 02/06/2023 16:13:45
推
02/06 23:30,
1年前
, 7F
02/06 23:30, 7F
→
02/06 23:32,
1年前
, 8F
02/06 23:32, 8F
→
02/06 23:33,
1年前
, 9F
02/06 23:33, 9F
→
02/06 23:36,
1年前
, 10F
02/06 23:36, 10F
推
02/06 23:53,
1年前
, 11F
02/06 23:53, 11F
→
02/06 23:55,
1年前
, 12F
02/06 23:55, 12F
我就是這樣做,但你這個例子也無法搬至 guizero 上
我前面有想搬 TakiDog 的例子,但發現無法找到 gather 的點
搬至 guizero 後我是要做到 UI 互動
也就是 task 1 要是個 loop 不斷跑
而 sync func 是由螢幕上的按鍵經使用者互動,guizero 會 call back
每 call back 一次,task 1 的 loop 就解鎖 condition 跑一次 do 1, do2, .....
你的例子,t_cond 不在 task1a 裡,所以 task1a 不是早就執行起來等
也不會是每經 t_cond call back 一次,task1a 就繞一次
稍微改一下就是我後來的解法了
推
02/07 01:00,
1年前
, 13F
02/07 01:00, 13F
推
02/07 01:04,
1年前
, 14F
02/07 01:04, 14F
→
02/07 01:04,
1年前
, 15F
02/07 01:04, 15F
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 才有意義
其實我在前面的討論裡都有提及這些,只是文筆不好,無法讓大家理解這個意思
但現在這篇應該能解釋了(我回去修文改成紅色的部份)
→
02/07 01:06,
1年前
, 16F
02/07 01:06, 16F
這個可以 XD
那我就是想法子利用這個 queue 去湊架構了...
剛草草看了底層 source code
不很清楚它怎麼做到 sync async 轉換的
----
這一面貼兩個程式我不會,是不是因為我沒註冊 XD
※ 編輯: HuangJC (1.168.18.180 臺灣), 02/08/2023 13:38:59
討論串 (同標題文章)
以下文章回應了本文:
完整討論串 (本文為第 2 之 4 篇):
Python 近期熱門文章
PTT數位生活區 即時熱門文章