关于利用go实现异步读写的写法分享

同步写法

    t := time.Now()
    fmt.Println("hello")
    skip := 3000
    for i := 1; i <= 51178; i += skip {
        fmt.Println(i)
        db.Model(DB.DBUserLog{}).Where("ul_id > ? ", i).Limit(skip).Find(&entityList)
        var buf bytes.Buffer
        for _, entity := range entityList {
            m := make(map[string]interface{})
            j, _ := json.Marshal(entity)
            _ = json.Unmarshal(j, &m)
            buf.Write(j)
            buf.WriteString("\n")
        }
        // 模拟写耗时操作
        time.Sleep(1 * time.Second)
    }
    elapsed := time.Since(t)
    fmt.Println("app run time", elapsed)

异步写法

    t = time.Now()
    go func() {
        skip := 3000
        for i := 1; i <= 51178; i += skip {
            fmt.Println(i)
            db.Model(DB.DBUserLog{}).Where("ul_id > ? ", i).Limit(skip).Find(&entityList)
            read <- entityList
        }
        readEnd <- 1
    }()
    write := func() {
        for {
            select {
            case data := <-read:
                var buf bytes.Buffer
                for _, entity := range data {
                    m := make(map[string]interface{})
                    j, _ := json.Marshal(entity)
                    _ = json.Unmarshal(j, &m)
                    buf.Write(j)
                    buf.WriteString("\n")
                }
                // 模拟写耗时操作
                time.Sleep(time.Second)
                _ = util.FilePutContents("ceshi.txt", buf.Bytes(), true)
                break
            case <-readEnd:
                return
            }
        }
    }
    write()
    elapsed = time.Since(t)
    fmt.Println("app run time", elapsed)

速度上当读操作和写操作的执行逻辑较为接近的时候效果较为明显。这种写法可以把一次读写看为一次操作,一次读写的用时变为了 min(readTime,writeTIme)。 而非 readTime + writeTime 。如果进行一些数据导出处理事,如果时间较长,且读写操作时间较为接近事可以尝试将读写异步话。这样除了中间 channel 中是阻塞的, 各自的读写操作逻辑是异步的。可以一定程度上提整体运行速度。如果读写操作用时相差较大,则优化效果就不那么明显了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
biubiubiu
讨论数量: 2
Makia98

既然是一个程序里的,那用mutex会不会更好呢?

2年前 评论
滚球兽进化 (楼主) 2年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!