關於利用go實現非同步讀寫的寫法分享

滾球獸進化發表於2021-12-02

同步寫法

    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 協議》,轉載必須註明作者和本文連結

相關文章