2017-08-16 179 views
-2

为了纯粹的教育目的,我创建了一个base58包。它将编码/使用bitcoin base58 symbol chart解码uint64,例如:如何同时迭代int范围

b58 := Encode(100) // return 2j 

num := Decode("2j") // return 100 

在创建我带着this的第一次测试:

func TestEncode(t *testing.T) { 
    var i uint64 
    for i = 0; i <= (1<<64 - 1); i++ { 
     b58 := Encode(i) 
     num := Decode(b58) 
     if num != i { 
      t.Fatalf("Expecting %d for %s", i, b58) 
     } 
    } 
} 

这种“幼稚”的实施,会尝试把所有的范围从uint64(从0到18,446,744,073,709,551,615)到base58,然后返回到uint64,但花费太多时间。

为了更好地理解go如何处理并发性,我想知道如何使用通道或goroutines并以最有效的方式在整个uint64范围内执行迭代?

数据是否可以通过块并行处理,如果是的话如何实现?

在此先感谢。

UPDATE

像由@Adrien在回答提到,一个方法是使用t.Parallel()但只是测试包时适用,在任何情况下,通过实现它,我发现这是明显慢了,它并行运行,但没有速度增益。

我明白,拼尽了全力uint64可能需要几年时间,但我想要的东西找到/现在怎么可能一个通道或够程,可能有助于加快这一进程(小范围1<<16测试)可能是通过使用这样的事情https://play.golang.org/p/9U22NfrXeq只是一个例子。

问题不在于如何测试软件包是关于什么算法,可以使用技术通过使用并发来更快地进行迭代。

+2

请注意,此测试也不能证明您的实现实际上是正确的;只有解码/编码匹配。如果他们都以同样的方式错误,测试将通过。您需要对照规范值进行测试以证明正确性。 – Adrian

+5

如果您的编码/解码能够在一个CPU上每秒完成10亿次转换(这非常乐观),您需要60个CPU才能在10年内完成此任务。这是假设从goroutines和渠道没有开销。 –

+0

@PaulHankin你是完全正确的,但我的想法是试图理解如何解决这个问题时,通过使用频道goroutines处理素数,尽管需要几年,我想了解更多关于如何优化。 – nbari

回答

0

我想出了这个解决方案:

package main 

import (
    "fmt" 
    "time" 

    "github.com/nbari/base58" 
) 

func encode(i uint64) { 
    x := base58.Encode(i) 
    fmt.Printf("%d = %s\n", i, x) 
    time.Sleep(time.Second) 
} 

func main() { 
    concurrency := 4 
    sem := make(chan struct{}, concurrency) 
    for i, val := uint64(0), uint64(1<<16); i <= val; i++ { 
     sem <- struct{}{} 
     go func(i uint64) { 
      defer func() { <-sem }() 
      encode(i) 
     }(i) 
    } 
    for i := 0; i < cap(sem); i++ { 
     sem <- struct{}{} 
    } 
} 

基本上,启动4名工人,并调用编码功能,为了更多地注意/理解这种行为,添加睡眠以便数据可以以大块4打印。

另外,这些答案帮助d我更好地了解并发理解:https://stackoverflow.com/a/18405460/1135424

如果有更好的方法,请让我知道。

1

此功能内置到围棋testing包,在T.Parallel形式:

func TestEncode(t *testing.T) { 
    var i uint64 
    for i = 0; i <= (1<<64 - 1); i++ { 
     t.Run(fmt.Sprintf("%d",i), func(t *testing.T) { 
      j := i   // Copy to local var - important 
      t.Parallel()  // Mark test as parallelizable 
      b58 := Encode(j) 
      num := Decode(b58) 
      if num != j { 
       t.Fatalf("Expecting %d for %s", j, b58) 
      } 
     }) 
    } 
} 
+0

感谢您指出T.Parrallel,但是您可以请修复示例以使其工作,如果我正确't.Run()'缺少''''第二个Itoa似乎不适用于'uint64':'不能在strconv.Itoa参数中使用i(type uint64)作为int类型参数' – nbari

+0

已更正的代码示例,但似乎您有这个想法。 – Adrian

+0

任何想法为什么当并行运行需要更多的时间(比较慢),而不是在t.Parallel()中运行? – nbari