# Is this the correct way to to calculate the final result ?

blov · · 30 次点击
<p>package main</p> <p>import ( &#34;fmt&#34; )</p> <p>func fib(a int64) int64 { if a &lt; 2 { return a } return fib(a-1) + fib(a-2) }</p> <p>func main() {</p> <pre><code>n1 := make(chan int64) s1 := make(chan int64) n2 := make(chan int64) s2 := make(chan int64) n3 := make(chan int64) s3 := make(chan int64) n4 := make(chan int64) s4 := make(chan int64) go func() { x := 49 n1 &lt;- int64(x) }() go func() { x := &lt;-n1 s1 &lt;- fib(x) }() go func() { x := 49 n2 &lt;- int64(x) }() go func() { x := &lt;-n2 s2 &lt;- fib(x) }() go func() { x := 45 n3 &lt;- int64(x) }() go func() { x := &lt;-n3 s3 &lt;- fib(x) }() go func() { x := 45 n4 &lt;- int64(x) }() go func() { x := &lt;-n4 s4 &lt;- fib(x) }() fmt.Println(&#34;Total fib sum &#34;, &lt;-s1+&lt;-s2+&lt;-s3+&lt;-s4) // waits all the goroutines to finish </code></pre> <p>Is there a much more simple solution ? </p> <hr/>**评论：**<br/><br/>tiberiousr: <pre><p>Calculating fibonacci numbers is not complex, why would you need all those goroutines?</p> <p>Also, you should probably use math/big because fibonacci numbers increase exponentially.</p> <pre><code>func Fibonacci() &lt;-chan *big.Int { c := make(chan *big.Int, 1) go func() { a, b := big.NewInt(0), big.NewInt(1) for { a.Add(a, b) a, b = b, a c &lt;- a } close(c) }() return c } </code></pre></pre>dlq84: <pre><blockquote> <p>true</p> </blockquote> <p>is unecessary here, </p> <pre><code> for { } </code></pre> <p>is valid Go</p></pre>tiberiousr: <pre><p>Good point, I wrote that function a couple of years ago when I was first learning. I should probably refactor some of that old code...</p></pre>Sythe2o0: <pre><p>There are a few potential improvements.</p> <ol> <li><p>You can use goroutines to calculate fibonacci if you want, but you don&#39;t need to send the inputs through channels.</p></li> <li><p>You&#39;re using extra lines to initialize variables you don&#39;t need to-- if you write a number in Go, Go will infer its type based on its context.</p></li> <li><p>You&#39;re calculating fib(45) and fib(49) twice, when you could just use the same result twice</p></li> <li><p>fib(45) is part of the result of fib(49), so by calculating both separately you&#39;re using a lot of extra time for duplicate work.</p></li> <li><p>As otherwise mentioned, using big ints will be needed at some point.</p></li> </ol> <p>This code incorporates the first three of the mentioned improvements:</p> <pre><code>package main import ( &#34;fmt&#34; ) func fib(a int64) int64 { if a &lt; 2 { return a } return fib(a-1) + fib(a-2) } func main() { s1 := make(chan int64) s3 := make(chan int64) go func() { s1 &lt;- fib(49) }() go func() { s3 &lt;- fib(45) }() fmt.Println(&#34;Total fib sum &#34;, 2*(&lt;-s1+&lt;-s3)) } </code></pre> <p>For the fourth improvement, a common strategy is to use memoization when you know you&#39;re going to be calculating the same expensive operations many times:</p> <pre><code>var ( fibMemo = map[int64]int64{ 0: 0, 1: 1, } ) func fib(a int64) int64 { if _, ok := fibMemo[a]; !ok { fibMemo[a] = fib(a-1) + fib(a-2) } return fibMemo[a] } </code></pre> <p>... but you&#39;ll want to use a sync.Map or a slice with defined bounds and null values if you are going to be doing this concurrently, not that that matters anymore, as once you&#39;ve calculated fib(49) you&#39;ll know fib(45).</p> <p>If we <a href="https://play.golang.org/p/1AhInet-B9" rel="nofollow">benchmark</a> these two approaches, memoization turns the problem from completely impractical to very quick:</p> <pre><code>BenchmarkFib1-8 1 53478058800 ns/op BenchmarkFib2-8 50000 27901 ns/op </code></pre></pre>rod1235: <pre><p>I was trying to port an haskell and scala code and doing some benchmarks Thank you all for the enlightment :) Now i know how to pass the result of an external funtion to a goroutine. Thank you so much. </p></pre>
0 回复

• 请尽量让自己的回复能够对别人有帮助
• 支持 Markdown 格式, **粗体**、~~删除线~~、``单行代码``
• 支持 @ 本站用户；支持表情（输入 : 提示），见 Emoji cheat sheet