【问题标题】:Go - Error when compiling a group of functionsGo - 编译一组函数时出错
【发布时间】:2015-12-14 22:32:41
【问题描述】:

我正在尝试实现一个非常简单的测试函数来验证来自我的欧拉问题解决方案的结果。

在下面的代码中,我创建了一个切片映射,在索引 0 上,我调用返回整数的函数,在索引 1 上,我调用该函数的结果。

package euler

import "testing"

func TestEulers(t *testing.T) {

    tests := map[string][]int{
        "Euler1": {Euler1(), 233168},
        "Euler2": {Euler2(), 4613732},
        "Euler3": {Euler3(), 6857},
        "Euler4": {Euler4(), 906609},
        "Euler5": {Euler5(), 232792560},
        "Euler6": {Euler6(), 25164150},
    }

    for key, value := range tests {
        if value[0] != value[1] {
            t.Errorf("%s\nExpected: %d\nGot:%d",
                key, value[0], value[1])
        }
    }
}

对于该地图,每个功能都可以正常工作并返回我期望的结果如果我一个接一个地运行,或者如果我评论这些键的一半/值。

例如,如果我用注释的这些行调用上面的函数,则测试将通过。

tests := map[string][]int{
    "Euler1": {Euler1(), 233168},
    // "Euler2": {Euler2(), 4613732},
    "Euler3": {Euler3(), 6857},
    "Euler4": {Euler4(), 906609},
    // "Euler5": {Euler5(), 232792560},
    // "Euler6": {Euler6(), 25164150},
} 

但是,例如,如果我将 cmets 安排在下一个方向,则测试不会。

tests := map[string][]int{
        //"Euler1": {Euler1(), 233168},
        "Euler2": {Euler2(), 4613732},
        "Euler3": {Euler3(), 6857},
        "Euler4": {Euler4(), 906609},
        //"Euler5": {Euler5(), 232792560},
        // "Euler6": {Euler6(), 25164150},
    }

测试会给我一个错误:

    WARNING: DATA RACE
Write by goroutine 6:
  runtime.closechan()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/runtime/chan.go:295 +0x0
  github.com/alesr/project-euler.Euler2()
      /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler.go:40 +0xd7
  github.com/alesr/project-euler.TestEulers()
      /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler_test.go:9 +0x46
  testing.tRunner()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:456 +0xdc

Previous read by goroutine 7:
  runtime.chansend()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/runtime/chan.go:107 +0x0
  github.com/alesr/numbers.FibonacciGen.func1()
      /Users/Alessandro/GO/src/github.com/alesr/numbers/numbers.go:103 +0x59

Goroutine 6 (running) created at:
  testing.RunTests()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:561 +0xaa3
  testing.(*M).Run()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:494 +0xe4
  main.main()
      github.com/alesr/project-euler/_test/_testmain.go:54 +0x20f

Goroutine 7 (running) created at:
  github.com/alesr/numbers.FibonacciGen()
      /Users/Alessandro/GO/src/github.com/alesr/numbers/numbers.go:105 +0x60
  github.com/alesr/project-euler.Euler2()
      /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler.go:27 +0x32
  github.com/alesr/project-euler.TestEulers()
      /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler_test.go:9 +0x46
  testing.tRunner()
      /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:456 +0xdc
==================
panic: send on closed channel

goroutine 36 [running]:
github.com/alesr/numbers.FibonacciGen.func1(0xc8200a01e0)
    /Users/Alessandro/GO/src/github.com/alesr/numbers/numbers.go:103 +0x5a
created by github.com/alesr/numbers.FibonacciGen
    /Users/Alessandro/GO/src/github.com/alesr/numbers/numbers.go:105 +0x61

goroutine 1 [chan receive]:
testing.RunTests(0x24d038, 0x2f7340, 0x1, 0x1, 0xf78401)
    /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:562 +0xafa
testing.(*M).Run(0xc82004df00, 0x1ff0e8)
    /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:494 +0xe5
main.main()
    github.com/alesr/project-euler/_test/_testmain.go:54 +0x210

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
    /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/runtime/asm_amd64.s:1696 +0x1

goroutine 35 [runnable]:
github.com/alesr/strings.Flip(0xc8200727a0, 0x6, 0x0, 0x0)
    /Users/Alessandro/GO/src/github.com/alesr/strings/strings.go:33 +0x17e
github.com/alesr/project-euler.Euler4(0x1ac9)
    /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler.go:73 +0x95
github.com/alesr/project-euler.TestEulers(0xc8200b6000)
    /Users/Alessandro/GO/src/github.com/alesr/project-euler/euler_test.go:11 +0x63
testing.tRunner(0xc8200b6000, 0x2f7340)
    /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:456 +0xdd
created by testing.RunTests
    /private/var/folders/q8/bf_4b1ts2zj0l7b0p1dv36lr0000gp/T/workdir/go/src/testing/testing.go:561 +0xaa4
exit status 2
FAIL    github.com/alesr/project-euler  0.022s

但是,我检查了每一个功能,它们都按预期工作。 如果需要,您可以访问Euler source code 或包numbersstrings

在 Euler2 函数中,我有一个 defer 语句来关闭从 FibonacciGen 接收的通道。

在 FibonacciGen 上,我确实有另一个 defer 语句来关闭同一通道。

这似乎是我的第一个错误。我应该只有一个而不是两个语句来关闭频道,因为他们试图关闭同一件事。对吗?

第二(这里我什至有点不确定),defer 语句会阻止函数在主 goroutine 返回之前被调用,对吗?如果我在主包上调用它,是否独立?

另外,因为数据是通过通道从 FibonacciGen 流向主函数。在我看来,如果我在 FibonacciGen 处关闭通道,我不需要通知主函数。但是如果我关闭主函数上的通道,我必须通知 FibonacciGen 停止尝试发送到该通道。

【问题讨论】:

  • Euler2 函数中,您关闭了FibonacciGen 生成的通道,但生成器不知道它并仍然尝试发送到已关闭的通道,如您所见,这很恐慌。您需要通知生成器停止写入该通道。
  • 但是如果我只运行 Euler2 函数,我不会得到任何错误。为什么?
  • goroutines 的调度很重要,尝试通过time.Sleep 休眠或通过runtime.Gosched 强制重新调度,以便其他 goroutine 可以继续。然后,您应该会看到同样的错误。
  • 运行go test -race

标签: debugging go concurrency compiler-errors goroutine


【解决方案1】:

在您的Euler2() 中,您不会检查频道是否已关闭。一旦它关闭,它就会被解除阻塞,因此它会尝试向现在关闭的通道发送一个值。

如果您只运行Euler2(),您的程序可能会在您将值发送到关闭的通道之前退出。

【讨论】:

    【解决方案2】:

    谢谢大家。在您的帮助下,我明白我以错误的方式关闭了频道。

    现在可以正常工作了。

    func Euler2() int {
    
        c := make(chan int)
        done := make(chan bool)
    
        go numbers.FibonacciGen(c, done)
    
        sum := 0
        var f int
    
        for {
            f = <-c
            if f < 4000000 {
                if f%2 == 0 {
                    sum += f
                }
            } else {
                close(done)
                return sum
            }
        }
    }
    
    func FibonacciGen(c chan int, done chan bool) {
    
        for {
            select {
            case <-done:
                return
            default:
                for i, j := 0, 1; ; i, j = i+j, i {
                    c <- i
                }
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-16
      • 2020-07-15
      • 2020-09-14
      • 2015-05-05
      • 1970-01-01
      • 1970-01-01
      • 2015-09-14
      相关资源
      最近更新 更多