1
cigarzh 2019-07-25 16:45:35 +08:00 via iPhone
i += 1
|
3
CEBBCAT 2019-07-25 17:02:25 +08:00 via Android
原子操作吗? 看了前两楼还是没太懂
|
4
ctrlaltdeletel 2019-07-25 17:09:52 +08:00
同一时刻只能有一个线程执行指的是 byte code 级别的执行,一个包含多个 byte code 的函数中仍有可能会发生线程调度的
|
5
jingxyy 2019-07-25 17:14:30 +08:00
就是原子性问题呗 虽然有 gil 但你想象一个场景 比如你对 list 做 append append 要做好几个操作 某个线程做了一部分的操作 然后切到另一个线程再做 append 这会有啥后果
|
6
bantao 2019-07-25 17:15:10 +08:00
cpu 支持并发,达到某些条件会线程切换,Python 因为 GIL 而不支持真正的并行,GIL 同一时刻( cpu 时间片)只允许一个线程,不是在一段时间内只允许一个线程执行。所以线程不安全的变量,在多线程环境中,可能在变量并未发生变化时,就被切换到另外一个线程中被使用了。https://www.zhihu.com/question/23030421
|
7
xianhu OP @jingxyy 真巧,针对这个场景,我刚刚用代码跑了一下 [启动 4 个线程,一个全局的 list 变量,每个线程都对这个 list 进行 append 操作 100000 次] 。跑完之后,对于这个 list 的长度没什么影响,里边的元素值也没什么影响,只是对元素的排列顺序有影响。
|
8
xianhu OP @xianhu 把这个实验中的 list 改为一个 int 值,每个线程对这个值进行+1 操作 100000 次,最终查看结果,发现值对不上。这就是 1 楼 i += 1 的意思。
|
10
wwqgtxx 2019-07-25 20:37:02 +08:00 1
@jingxyy @xianhu python 官方文档提到了在 cpython 的实现中 list 的 append 是原子的
https://docs.python.org/3.7/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe |
11
wwqgtxx 2019-07-25 20:41:21 +08:00
其实一个操作是不是原子的有两种评判标准:
1、对于纯 Python 代码,是不是只有一条 byte code 2、对于 C 实现的函数,内部有没有释放 GIL |
12
hhhsuan 2019-07-25 20:43:01 +08:00 via Android
忘了 Python 线程吧,直接用进程
|
13
whoami9894 2019-07-25 21:02:01 +08:00
@hhhsuan 不是 CPU 密集运算干嘛用多进程? I/O 操作的单核线程并发相比进程开销要高效的多
|
14
Hopetree 2019-07-25 22:17:00 +08:00
@hhhsuan 你用过 python 吗?知道什么时候用线程什么时候用进程吗?不知道就别乱说
还有,那些喜欢拿 python 的 GIL 说事情的人麻烦好好看看自己的代码有没有资格被 GIL 影响 |
16
bilibilifi 2019-07-26 05:58:16 +08:00 via iPhone
@whoami9894 感觉 python 的 multprocessing 确实有黑科技,试过把主 loop 用 prange 重写只快了百分之 30
|
18
oahebky 2019-07-26 08:53:58 +08:00
用 C 语言写的多线程在十几二十年前的单核 CPU 的电脑上运行,需不需要保证线程安全呢???
(同理,用其它语言写多线程在单核 CPU 上运行需不需要保证线程安全呢?) 现在搞不清楚也没关系,多看书,看看名校公开课,写写代码,逐渐就有概念了。 |
19
cwjokaka 2019-07-26 10:02:51 +08:00
因为多线程之间会进行上下文切换,执行非原子操作的时候可能在过程中挂起当前线程,之后继续执行的的时数据可能已不是最新了
|
24
wwqgtxx 2019-07-26 19:03:24 +08:00 via iPhone
@hhhsuan 在保证一个 fd 只会被一个线程操作的情况下,传递 fd 没有任何糟糕的,如果你觉得糟糕,那只能说明你程序写的烂
|