golang 并发demo 写入 redis

原文链接:golang 并发demo 写入 redis

源代码:

package main

import (
    "fmt"
    "runtime"
    "strconv"
    "time"

    "gopkg.in/redis.v3"
)

var (
    jobnum = runtime.NumCPU()
    //每次写入redis的数量
    //除以 jobnum 为了保证改变了任务数, 总量不变, 便于测试
    procnum = 100000 / jobnum
)

type Job struct {
    ID     string
    Client *redis.Client
    Result chan<- string
}

func waitJobs(dones <-chan struct{}, results chan string) {
    working := jobnum
    done := false
    for {
        select {
        case result := <-results:
            println(result)
        case <-dones:
            working--
            if working <= 0 {
                done = true
            }
        default:
            if done {
                return
            }
        }
    }
}

func initClient(poolSize int) *redis.Client {
    client := redis.NewClient(&redis.Options{
        Addr:         "localhost:6379",
        DialTimeout:  time.Second,
        ReadTimeout:  time.Second,
        WriteTimeout: time.Second,
        PoolSize:     poolSize,
        Password:     "123.com",
        DB:           0,
    })
    if err := client.FlushDb().Err(); err != nil {
        panic(err)
    }
    return client
}

func main() {
    start := time.Now()
    fmt.Println("start:", start)
    defer func() {
        end := time.Now()
        fmt.Println("end:", end)
        fmt.Println("jobs num:", jobnum, "total items:", jobnum*procnum)
        fmt.Println("total seconds:", end.Sub(start).Seconds())
    }()

    //任务channel 定义缓冲器为job数量
    jobs := make(chan Job, jobnum)
    //存放结果
    results := make(chan string, jobnum*procnum)
    //每个任务完成之后给dones发送一次
    dones := make(chan struct{}, jobnum)

    client := initClient(10)
    defer client.Close()

    //定义每个任务执行的方法
    jobfunc := func(client *redis.Client, id string) (string, error) {
        defer func() {
            //完成之后向 dones 发送数据
            dones <- struct{}{}
            //fmt.Println("job id:", id, "完成")
        }()

        //写入 procnum 条数据
        for idx := 0; idx < procnum; idx++ {
            key := id + "-" + strconv.Itoa(idx)

            _, err := client.Set(key, time.Now().String(), 0).Result()
            if err != nil {
                return "", err
            }
            //fmt.Println("key:", key, " | result:", val, " | error:", err)
        }

        return "ok", nil
    }

    //1 添加 job 到 channel
    go func() {
        for index := 0; index < jobnum; index++ {
            jobs <- Job{strconv.Itoa(index), client, results}
        }
        defer close(jobs)
    }()

    //2 并行执行 jobs
    for j := range jobs {
        go func(job Job) {
            jobfunc(client, job.ID)
            job.Result <- "ok"
        }(j)
    }

    //3 等待所有任务完成
    waitJobs(dones, results)
}

运行结果:

[root@localhost 111]# go run redis.go 
start: 2019-09-24 08:26:34.614166323 +0000 UTC m=+0.001802059
ok
ok
ok
ok
ok
ok
ok
ok
end: 2019-09-24 08:26:35.655656884 +0000 UTC m=+1.043292369
jobs num: 8 total items: 100000
total seconds: 1.04149031

8 个 goroutine: 1s 完成10w数据写入

posted @ 2019-09-24 16:28  salami_china  阅读(1747)  评论(0编辑  收藏  举报