zoukankan      html  css  js  c++  java
  • golang 串行与并行(并发)对比

    golang对比其它语言最大的优势就是并行计算(一个go就能实现并发),工作中经常遇到并发的场景, 具体实现并发的方式有多种,今天就来做个小实验来对比说明串行和并行执行任务中并发的优势,好了直接上代码

    package main
    
    import (
        "fmt"
        "math/rand"
        "sync"
        "time"
    )
    
    //定义任务数量
    var jobsCount int = 10
    
    func main() {
        timer("serial", serial)
        timer("parallel", parallel)
        timer("parallel2", parallel2)
    }
    
    //串行实现任务执行
    func serial() {
        for i := 0; i < jobsCount; i++ {
            fmt.Printf("hello  task %d 
    ", i)
            a := int(rand.Float64() * 1000.0)
            a = 500 //可注释掉该行使用随机数
            time.Sleep(time.Duration(a) * time.Millisecond)
        }
        fmt.Println("serial task done success ")
    }
    
    //使用waitgroup 来实现等待并发完成
    func parallel() {
        wg := sync.WaitGroup{}
        for i := 0; i < jobsCount; i++ {
            wg.Add(1)
            go func(idx int) {
                fmt.Printf("hello  task %d 
    ", idx)
                a := int(rand.Float64() * 1000.0)
                a = 500 //可注释掉该行使用随机数
                time.Sleep(time.Duration(a) * time.Millisecond)
                wg.Done()
            }(i)
        }
        wg.Wait()
        fmt.Println("parallel task done success ")
    }
    
    //使用chanel 来实现并发
    func parallel2() {
        ch := make(chan int)
        //done := make(chan int)
        for i := 0; i < jobsCount; i++ {
            go DoTask(i, ch)
        }
    
        for i := 0; i < jobsCount; i++ {
            fmt.Printf(" task %d done 
    ", <-ch)
        }
    }
    
    //我是完成耗时工作的
    func DoTask(taskid int, ch chan int) {
        fmt.Printf("task %d doing !!!!!!!!!!!!!
    ", taskid)
        a := int(rand.Float64() * 1000.0)
        a = 500
        time.Sleep(time.Duration(a) * time.Millisecond)
        ch <- taskid
    }
    
    //测量函数执行时间
    func timer(funcName string, f func()) {
        t1 := time.Now()
        f()
        fmt.Printf("%s  fun cost  %s 
    ", funcName, time.Now().Sub(t1))
    }

    这里假设要完成十个耗时的任务,每个任务需要500ms或者随机时间,分别用串行和两个并行函数来完成; 

    串行执行的顺序就是每个任务执行完才能执行下个任务,并行执行就是十个任务同时执行不分先后(可以认为同时开始),

    使用计时器对每个函数执行时间进行度量, 

    main 启动后,查看控制台上结果的输出:

    hello  task 0 
    hello  task 1 
    hello  task 2 
    hello  task 3 
    hello  task 4 
    hello  task 5 
    hello  task 6 
    hello  task 7 
    hello  task 8 
    hello  task 9 
    serial task done success 
    serial  fun cost  5.0042001s 
    hello  task 9 
    hello  task 4 
    hello  task 5 
    hello  task 6 
    hello  task 7 
    hello  task 8 
    hello  task 2 
    hello  task 0 
    hello  task 3 
    hello  task 1 
    parallel task done success 
    parallel  fun cost  500.0504ms 
    task 9 doing !!!!!!!!!!!!!
    task 4 doing !!!!!!!!!!!!!
    task 3 doing !!!!!!!!!!!!!
    task 6 doing !!!!!!!!!!!!!
    task 7 doing !!!!!!!!!!!!!
    task 8 doing !!!!!!!!!!!!!
    task 1 doing !!!!!!!!!!!!!
    task 0 doing !!!!!!!!!!!!!
    task 2 doing !!!!!!!!!!!!!
    task 5 doing !!!!!!!!!!!!!
     task 3 done 
     task 4 done 
     task 1 done 
     task 9 done 
     task 2 done 
     task 0 done 
     task 7 done 
     task 8 done 
     task 6 done 
     task 5 done 
    parallel2  fun cost  500.3297ms 
    
    Process finished with exit code 0

    从控制台上我们可以看到串行执行的话,每个任务500ms ,总任务执行了5s ,

    并行执行的话,两个并行并没有顺序,每个任务500ms,总任务也可以认为是500ms,

    串行的代码10行,并行的代码分别为 15行和20行 ,相比之下时间上后者是前者的1/10,这就是并行的巨大优势,因此我们要多审视自己的代码,避免偷懒,面对高并发场景下才能实现高效完成任务; 

     新增循环中使用管道chanel的形式

    //使用chan 接收等待任务完成(缺点:增加开销)
    func paralle3() {
        //ch := make(chan int, jobsCount)
        ch := make(chan int)
        for i := 0; i < jobsCount; i++ {
            go func(idx int) {
                fmt.Printf("hello  task %d 
    ", idx)
                a := int(rand.Float64() * 1000.0)
                a = 500 //可注释掉该行使用随机数
                time.Sleep(time.Duration(a) * time.Millisecond)
                ch <- idx
            }(i)
        }
        for i := 0; i < jobsCount; i++ {
            fmt.Printf(" task %d done 
    ", <-ch)
        }
        fmt.Println("paralle3 task done success ")
    }

  • 相关阅读:
    第二次作业
    大学——新生活方式
    第四次作业
    第三次作业
    第二次作业——起航
    梦开始的地方
    第四次作业
    第三次作业
    第二次作业
    博客作业 随笔
  • 原文地址:https://www.cnblogs.com/lavin/p/golang-Goroutines.html
Copyright © 2011-2022 走看看