2015-12-14 96 views
1

我試圖實現一個非常簡單的測試函數來驗證來自我的歐拉問題解決方案的結果。Go - 編譯一組函數時出錯

在下面的代碼中,我創建了一張切片圖,其中索引爲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}, 
} 

但是,如果我安排在下一個方式的意見,例如,測試不會。

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函數我有一個延遲語句來關閉從FibonacciGen接收的通道。

而在FibonacciGen上,我確實有另一個延遲語句來關閉同一個通道。

看來這是我的第一個錯誤。我應該只有一個而不是兩個聲明來關閉這個頻道,因爲他們試圖關閉同一個事物。那是對的嗎?

其次(在這裏我甚至有點不確定),延遲語句將阻止函數在主要goroutine返回之前被調用,對吧?獨立的,如果我打包的主要或不是?

另外,由於數據正在流過從FibonacciGen到主函數的通道。在我看來,如果我關閉了FibonacciGen的頻道,我不需要通知主函數。但是,如果我關閉主要功能的頻道,我必須通知斐波納契Gen停止嘗試發送到此頻道。

+3

在'Euler2'功能,您封閉的通道通過'FibonacciGen'產生,但發電機不知道這件事,仍然試圖發送到恐慌當你看到封閉的通道。您需要通知發電機停止寫入該頻道。 –

+1

但是,如果我只運行歐拉2功能,我會得到沒有錯誤。爲什麼? –

+0

goroutine的調度很重要,通過'time.Sleep'或者'runtime.Gosched'強制重新調度,以便其他goroutine可以繼續。然後,你應該看到同樣的錯誤。 –

回答

0

謝謝大家。在你的幫助下,我可以理解我以錯誤的方式關閉了頻道。

現在工作正常。

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 
      } 
     } 
    } 

} 
1

在您的Euler2()中,您不檢查頻道是否已關閉。關閉後,它將被解鎖,因此它會嘗試向現在已關閉的頻道發送一個值。

如果您只運行Euler2()您的程序可能會在您將值發送到關閉的通道之前退出。