• 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数据写入

  • 相关阅读:
    Java StringBuilder、基本类型的包装类
    立个Flag不学好PHP誓不罢休
    LAMP搭建 转
    CentOS使用yum源中自带的rpm包安装LAMP环境
    CentOS RedHat YUM 源扩展补充(32位、64位均有)
    解决phpmyadmin上传文件大小限制的配置方法
    lanmp v2.5一键安装包发布(包括lamp,lnmp,lnamp安装)
    图像处理 jpg png gif svg
    NAT模式/路由模式/全路由模式 (转)
    网页制作中绝对路径和相对路径的区别
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/11579059.html
Copyright © 2020-2023  润新知