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