我是 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 routine 运行 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 循环都无关紧要)将比循环的其余部分慢得多。这是有原因的吗?(执行时间以纳秒为单位)编辑:删除开关部分,因为人们对这个问题感到困惑。
1 回答
墨色风雨
TA贡献1853条经验 获得超6个赞
并发不是并行。通道的这种特殊使用结果与仅从 返回值非常相似removeDuplicates
,只是两个 goroutine 需要协调它们对通道的使用会产生额外的开销。
具体来说:
循环的每次迭代都有自己的通道,每个通道只能容纳一个元素。
在所有语句都已执行之前,循环无法继续下一次迭代,包括对该语句的调用
log.Printf
阻塞,直到从通道接收到值。removeDuplicates
检测到实时时间已经过去了多少,而不是在解决问题上花费了多少时间。这是评论说它首先不是一个很好的基准的众多原因之一。
推测:在循环的前几次迭代中,goroutine 可能removeDuplicates
会初始化start
,然后将执行时间交给主 goroutine。然后 main goroutine 立即检查 mutex on c
,发现它还不能做任何事情,并返回给调度程序,所有这些检查和上下文切换增加了数千纳秒(关心这通常是微基准测试的味道)到goroutineremoveDuplicates
的实时执行。main
在几次迭代之后,某些东西(也许是 Go 运行时)发现了在返回之前永远无法取得进展的事实removeDuplicates
,并且避免了上下文切换。
我知道此时您对解释比建议更感兴趣,但如果我不指出比较 Go 和 Java 的基准已经存在,我会觉得很不负责任。即使您想自己编写,我也建议使用类似的方法:根据需要完成的任务定义基准程序,然后使用每种语言(或框架)中可用的最佳工具来完成工作具有良好的性能。
- 1 回答
- 0 关注
- 89 浏览
添加回答
举报
0/150
提交
取消