我是golang的新手,在执行此poc时,我注意到在运行for循环时出现了奇怪的行为。
package main;
import (
"log"
"strings"
"time"
)
type data struct {
elapseTime int64
data string
}
func main(){
for i := 0 ; i < 10; i++{
c := make(chan data);
go removeDuplicates("I love oranges LALALA I LOVE APPLES LALALA XD", c);
log.Printf("%v", <- c);
}
}
func removeDuplicates(value string , c chan data){
start := time.Now();
var d = data{};
var r string;
value = strings.ToLower(value);
var m = make(map[string]string);
splitVals := strings.Split(value, " ");
for _, element := range splitVals {
if _, ok := m[element]; ok == false {
m[element] = element;
}
}
for k, _ := range m {
r = r + k + " ";
}
d.data = strings.TrimRight(r, "");
d.elapseTime = time.Since(start).Nanoseconds();
c <- d;
}
有效地,我要达到的目的是删除简单字符串的重复项,并将这些信息与花费的时间一起打印出来。循环运行go例程10次,等待响应通过通道到达。
2019/05/24 00:55:49 {18060 i love oranges lalala apples xd }
2019/05/24 00:55:49 {28930 love oranges lalala apples xd i }
2019/05/24 00:55:49 {10393 i love oranges lalala apples xd }
2019/05/24 00:55:49 {1609 oranges lalala apples xd i love }
2019/05/24 00:55:49 {1877 i love oranges lalala apples xd }
2019/05/24 00:55:49 {1352 i love oranges lalala apples xd }
2019/05/24 00:55:49 {1708 i love oranges lalala apples xd }
2019/05/24 00:55:49 {1268 apples xd i love oranges lalala }
2019/05/24 00:55:49 {1736 oranges lalala apples xd i love }
2019/05/24 00:55:49 {1037 i love oranges lalala apples xd }
这就是我所看到的:循环的前几个打印(无论是单循环还是100x循环都没关系)将比其余循环慢得多。为什么会这样呢? (执行时间以十亿分之一秒为单位)
编辑:由于人们对该问题感到困惑,因此删除了开关部分。
答案 0 :(得分:2)
Concurrency is not parallelism.通道的这种特殊用法与从removeDuplicates
返回值非常相似,只不过两个goroutine需要额外的开销来协调它们对通道的使用。
特别是:
log.Printf
的调用将阻塞,直到从通道接收到值为止),循环才能继续进行下一次迭代。removeDuplicates
会检测到已花费了多少实时时间,而不是花费了多少时间来解决问题。这是评论最初说它不是一个很好的基准的众多原因之一。 推测性::在循环的前几次迭代中,removeDuplicates
goroutine可能会初始化start
,然后产生执行时间到主goroutine。然后,主goroutine立即检查c
上的互斥锁,发现它仍然无法执行任何操作,并退回给调度程序,所有这些检查和上下文切换会增加数千纳秒的时间(通常需要注意的是removeDuplicates
goroutine的实时执行。经过几次迭代后,main
直到removeDuplicates
返回之前才能够取得进展,并且避免了上下文切换。(p,可能是Go运行时)。
我知道您目前对解释的兴趣远胜于建议。,但如果我不指出将Go和Java进行比较的基准microbenchmarking,我会感到非常不负责任。即使您想编写自己的代码,我也建议您使用类似的方法:根据需要完成的任务定义基准程序,然后使用每种语言(或框架)中可用的最佳工具来完成工作具有良好的性能。