给Prometheus修了几处typo,并入主分支后居然看到了RSC…



看了一下他的改动,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
scrape: fix two loop variable scoping bugs in test
Consider code like:

for i := 0; i < numTargets; i++ {
stopFuncs = append(stopFuncs, func() {
time.Sleep(i*20*time.Millisecond)
})
}

Because the loop variable i is shared by all closures,
all the stopFuncs sleep for numTargets*20 ms.

If the i were made per-iteration, as we are considering
for a future Go release, the stopFuncs would have sleep
durations ranging from 0 to (numTargets-1)*20 ms.

Two tests had code like this and were checking that the
aggregate sleep was at least numTargets*20 ms
("at least as long as the last target slept"). This is only true
today because i == numTarget during all the sleeps.

To keep the code working even if the semantics of this loop
change, this PR computes

d := time.Duration((i+1)*20) * time.Millisecond

outside the closure (but inside the loop body), and then each
closure has its own d. Now the sleeps range from 20 ms
to numTargets*20 ms, keeping the test passing
(and probably behaving closer to the intent of the test author).

The failure being fixed can be reproduced by using the current
Go development branch with

GOEXPERIMENT=loopvar go test


即在 循环&闭包 中,time.Sleep()中包含迭代变量i,现在是会按照迭代完成后最终的i的值去sleep (Because the loop variable i is shared by all closures)。 之后Go准备改成按照当时迭代的值(而非最终)去sleep。

即如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"time"
)

func main() {

now := time.Now()
numTargets := 10
stopFuncs := []func(){}

for i := 0; i < numTargets; i++ {
stopFuncs = append(stopFuncs, func() {
time.Sleep(time.Duration(i*2) * time.Second)
})
}

f := stopFuncs[1]
f()

fmt.Println(stopFuncs)

fmt.Println("时间间隔:", time.Since(now))

}

当前输出:


可能几个版本之后 如上代码中的时间间隔就会输出 2s

项目中一般不太会这样用,需要满足 在for循环中使用闭包,闭包中有time.Sleep()且使用了迭代的变量i


不过翻了下issue中的proposal,​没有找到