Python GIL 的问题

2023-09-03 23:04:54 +08:00
 jenrey

如下图所示,Python 使用 GIL 也会出现图中这样的问题,那么 GIL 存在的意义是什么?谢谢 https://imgur.com/a/YCoqzm1

2205 次点击
所在节点    Python
16 条回复
liprais
2023-09-03 23:05:52 +08:00
你的意思是单核 cpu 就不能有多线程了?
iseki
2023-09-03 23:07:39 +08:00
原始链接呢,原文呢,按理说不该有这样的问题
jenrey
2023-09-03 23:26:48 +08:00
@liprais 我感觉图中的意思,只是想表达 Python GIL 在单核 CPU 下进行多线程并发,仍需要给 obj 对象加锁。
而 Python GIL 的诞生 只是为了解决 在多核 CPU 下执行多线程“并行”任务时 Python 的引用计数器不是线程安全 的问题。也就是说 Python GIL 的出现让多核 CPU 下执行多线程 并发 任务时引用计数器是线程安全的。
所以,这个图配得不好,应该加个标题《即使有 Python GIL ,我们仍需给共享对象加锁,无论 CPU 核心数》。
不知道我理解的对不对。
wevsty
2023-09-03 23:47:13 +08:00
单核时代一样可以多进程,多线程。
线程的调度是由 OS 来决定的,跟你有几个 CPU 核心没有必然的关系。
lovelylain
2023-09-04 00:11:34 +08:00
@jenrey 写过多线程程序没?多线程环境下操作同一个对象,为了避免线程安全问题,最常见的方案就是加锁,Python GIL 同理,如果编译为不支持多线程,是不需要 GIL 的,但支持多线程后,为了避免引用技等出现
lovelylain
2023-09-04 00:14:49 +08:00
@jenrey 写过多线程程序没?多线程环境下操作同一个对象,为了避免线程安全问题,最常见的方案就是加锁,Python GIL 同理,如果编译为不支持多线程,是不需要 GIL 的,但支持多线程后,为了避免引用计数等出现线程安全问题,就引入了 GIL ,单核 CPU 也可以多线程
也存在线程安全问题的。
jackOff
2023-09-04 01:48:25 +08:00
Python 全局解释器导致了多线程大多数情况就是个笑话,仅仅在网络通信和读写文件上能稍微体现一点。其他方面使用它还不如使用异步编程,当然多进程可以改善这种情况,但是这就是使代码开发变得极度简单化的一个代价
mylifcc
2023-09-04 02:02:11 +08:00
GIL 是解释器级别的锁,可以保证同一时间只有 1 个线程在 CPU 运行来改这个参数,如果用 GO 就可能会有多个线程在同时改了,这样说你懂了吧。。。这个问题属于业务级别的问题,归根结底是设计问题,你允不允许非同一时间的线程来改一个值的,如果允许,就不需要加锁,因为你业务就是这么设计的。
ysc3839
2023-09-04 02:59:59 +08:00
不会出现图中的问题,加锁之后需要持有锁的线程主动解锁,此时如果切换到了线程 B ,线程 B 没法锁定,就只能等待。
est
2023-09-04 09:07:18 +08:00
你说下这图谁画的吧。我让作者出来给你解释。
itskingname
2023-09-04 09:55:46 +08:00
我以前写过一篇文章来说明这个问题: https://mp.weixin.qq.com/s/a37OxUjgHdps1ZsPB7pKcQ
sujin190
2023-09-04 10:35:31 +08:00
GIL 限制的是单个字节码级别的原子操作不能并发,就算是简单 a+=1 这样的也是需要多条字节码指令的,所以也不能保证是原子操作,并不是你想的那种给对象加锁,你可以用 dis 模块研究下代码和编译生成的字节码对应关系
jenrey
2023-09-04 13:19:30 +08:00
@ysc3839 所以我感觉原图和 GIL 锁的原理没啥关系,只是表明 Python 有了 GIL 后,在多线程下是并发执行的,而非并行执行,与 CPU 的核心数也无关系,只会采用单核心时间片调度多个线程,所以只是个提醒图(提醒如果不给共享对象加锁,会出问题而已)
引用计数器的方案有瑕疵,即 当两个线程同时提高同一个对象的引用计数时,(如果没有 GIL 锁)那么引用计数只会被提高了 1 次而不是 2 次。所以 GIL 就诞生了。
NoAnyLove
2023-09-04 16:20:36 +08:00
不会出现这种问题,GIL 会保证每条指令的执行是 atomic 的,可以看看 https://www.v2ex.com/t/965954

如果主动撤销对某个 obj 的引用,多半是是使用`del obj`语句(也可能是其他语句),也就是一条 DELETE_NAME (或者别的 DELETE 指令)。减少引用和具体的回收工作都在这一条指令中完成了,

```
>>> import dis
>>> dis.dis("del obj")
1 0 DELETE_NAME 0 (obj)
2 LOAD_CONST 0 (None)
4 RETURN_VALUE
```
akaHenry
2023-09-06 10:28:46 +08:00
GIL 不防呆.
Cu635
2023-09-27 11:35:42 +08:00
链接里面的图是用什么画的?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/970605

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX