作者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