当前位置:网站首页>n++也不靠谱
n++也不靠谱
2022-07-04 12:34:00 【小锟哥哥】

今天小明又去面试了,又被问了一个奇怪的面试题:
n := 0
for i := 0; i < 1000000; i++ {
go func() {
n++
}()
}
fmt.Println(n)
到你思考的时间了,输出啥结果呢?
小明思考了许久,给出了他的回答:不知道,然后面试官就告诉他:你通过了。
是不是有点离谱,没错,这个代码的结果就是不知道,每次执行的结果都不一样,全看 cpu 咋调度。
且听我来给客官慢慢道来。
一、最开始的原型
我们根据面试代码,往回滚一点,看下这样的代码:
n := 0
for i := 0; i < 1000000; i++ {
func() {
n++
}()
}
fmt.Println(n)
我们把协程拿掉,现在的结果是不是就很好知道了,没错就是循环的次数 1000000。
二、里面的坑
我们再回到面试的代码,这里面其实有两个坑:
第一个坑:他没加协程等待,所以很可能一扫而过,还没循环几次主程序就结束了,甚至是一次循环都没做就退出了。
但是在面试中,一般不提这个坑,这不是面试的重点,当然你也可以提一下。
第二个坑就是面试的重点了:
在不考虑主线程提前退出的问题,就是加入协程后,n++ 的结果不准确了。
为什么呢?
因为 n++ 并不是原子的,他要完成 n++ 的操作他需要做三步:
从内存里面取出值 执行 +1 操作 赋值回去
因为他不是原子的,所以很可能在你取值的时候别的线层也在取值,也在进行计算,最后赋值时就会被覆盖,从而出现随机不可预算的结果。
三、该怎么保证结果呢?
因为 n++ 不是原子的,如果我们要让他变原子,常见的操作有两种:
1、加锁
首先我们为了保证他能把循环执行完毕,需要加个 wait:
wg := sync.WaitGroup{}
n := 0
for i := 0; i < 1000000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
n++ //不是原子的 1、从内存读出 2、n++ 3、赋值
}()
}
wg.Wait()
fmt.Println(n)
这样就能让他执行完毕了,再加入我们的线层锁:
wg := sync.WaitGroup{}
locker := sync.Mutex{}
n := 0
for i := 0; i < 1000000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// 锁
defer locker.Unlock()
locker.Lock()
n++ //不是原子的 1、从内存读出 2、n++ 3、赋值
}()
}
wg.Wait()
fmt.Println(n)
这样执行的结果,每次都是执行的次数了。
2、使用 atomic
我们偶尔还会使用 atomic 包来处理这类操作,但是也有一定局限,他支持的数据类型有限。
直接上代码:
var n int32 = 0
for i := 0; i < 1000000; i++ {
func() {
atomic.AddInt32(&n, 1) //原子操作
}()
}
fmt.Println(n)
这里我们把 n 变成了 int32 类型,这样的运行结果也能保证是循环的次数。
边栏推荐
- C language function
- 阿里云有奖体验:用PolarDB-X搭建一个高可用系统
- Implementation mode and technical principle of MT4 cross platform merchandising system (API merchandising, EA merchandising, nj4x Merchandising)
- CTF竞赛题解之stm32逆向入门
- Wechat video Number launches "creator traffic package"
- jsonp
- Kivy tutorial 08 countdown app implements timer call (tutorial includes source code)
- C语言数组
- Complementary knowledge of auto encoder
- DC-5靶机
猜你喜欢

Show recent errors only command /bin/sh failed with exit code 1
![Cadence physical library lef file syntax learning [continuous update]](/img/d5/0671935b074e538a2147dbe51a5a70.jpg)
Cadence physical library lef file syntax learning [continuous update]

16. Memory usage and segmentation

Leetcode day 17

Communication tutorial | overview of the first, second and third generation can bus

2022, 6G is heating up

PostgreSQL 9.1 飞升之路

Runc hang causes the kubernetes node notready

Master the use of auto analyze in data warehouse

DC-5靶机
随机推荐
分布式事务相关概念与理论
It's hard to hear C language? Why don't you take a look at this (V) pointer
I want to talk about yesterday
游戏启动后提示安装HMS Core,点击取消,未再次提示安装HMS Core(初始化失败返回907135003)
Bottom Logic -- Mind Map
runc hang 导致 Kubernetes 节点 NotReady
MySQL performance optimization index
The detailed installation process of Ninja security penetration system (Ninjitsu OS V3). Both old and new VM versions can be installed through personal testing, with download sources
众昂矿业:为保障萤石足量供应,开源节流势在必行
数据库锁表?别慌,本文教你如何解决
Interview question MySQL transaction (TCL) isolation (four characteristics)
Practice of retro SOAP Protocol
[leetcode] 96 and 95 (how to calculate all legal BST)
Iterm tab switching order
17.内存分区与分页
The solution of permission denied
记一次 Showing Recent Errors Only Command /bin/sh failed with exit code 1 问题
Master the use of auto analyze in data warehouse
C语言:求100-999是7的倍数的回文数
一文掌握数仓中auto analyze的使用