Golang循环初始速度慢于其余

博基:

我是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循环都没关系)将比其余循环慢得多。为什么会这样呢?(执行时间以十亿分之一秒为单位)

编辑:由于人们对此问题感到困惑,因此删除了开关部分。

Jesse Amano:

并发不是并行性。事实证明,通道的这种特殊用法与从中返回值非常相似removeDuplicates,除了两个goroutine需要额外的开销来协调它们对通道的使用。

特别:

  • 循环的每次迭代都有其自己的通道,并且每个通道只能容纳一个元素。
  • 直到所有语句执行完毕,包括对log.Printf的调用,直到从通道接收到值,循环才能继续进行下一次迭代
  • removeDuplicates可以检测到已经花费了多少实时时间,而不是花费了多少时间来解决问题。这是评论最初说它不是一个很好的基准的众多原因之一。

推测性的:在循环的前几次迭代中,removeDuplicatesgoroutine可能会初始化start,然后产生执行时间到主goroutine。然后,主要的goroutine立即检查互斥锁c,发现它仍然无法执行任何操作,并退回给调度程序,所有这些检查和上下文切换会增加数千纳秒的时间(注意这通常是一种微基准测试的味道)。该removeDuplicates够程的实时执行。经过几次迭代后,某些事情(可能是Go运行时)在main无法removeDuplicates返回直到返回之前无法取得进展的事实上得到了回报,并且避免了上下文切换。

我知道您此时对解释的兴趣远胜于建议,但如果我不指出将Go与Java进行比较的基准已经存在,那我将不负责任即使您想编写自己的代码,我也建议您使用类似的方法:根据需要完成的任务定义基准程序,然后使用每种语言(或框架)中可用的最佳工具来完成工作表现良好。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章