iris 抽奖实例4

2021-08-09  本文已影响0人  码农工号9527

支付宝集福卡

package main

import (
    "fmt"
    "github.com/kataras/iris/v12"
    "github.com/kataras/iris/v12/mvc"
    "log"
    "math/rand"
    "os"
    "strconv"
    "strings"
    "time"
)

// 奖品对象
type gift struct {
    id       int      //奖品标识
    name     string   //奖品名称
    pic      string   //奖品图片
    link     string   //奖品链接
    inuse    bool     // 是否使用中
    rate     int      //中将概率,万分之N,0~9999
    rateMin  int      //大于等于最小中奖编码
    rateMax  int      //小于等于最大中奖编码
}

// 最大号码
const rateMax = 10

var logger *log.Logger

type lotterController struct {
    Ctx iris.Context
}

func main() {
    app := newApp()
    app.Run(iris.Addr(":8080"))
}

// 初始化奖品列表信息(管理后台来维护)
func newGift() *[5]gift {
    /**
     * 表达式new(T)将创建一个T类型的匿名变量,所做的是为T类型的新值分配并清零一块内存空间,
     * 然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的T类型值的指针值,
     * 返回的指针类型为*T。
     *
     * 我们只需使用new()函数,无需担心其内存的生命周期或怎样将其删除,因为Go语言的内存管理系统会帮我们打理一切。
     */
    giftlist := new([5]gift)
    // 1 实物大奖
    g1 := gift{
        id:      1,
        name:    "富强福",
        pic:     "富强福.jpg",
        link:    "",
        inuse:   true,
        rate:    4,
        rateMin: 0,
        rateMax: 0,
    }
    giftlist[0] = g1
    // 2 实物小奖
    g2 := gift{
        id:      2,
        name:    "和谐福",
        pic:     "和谐福.jpg",
        link:    "",
        inuse:   true,
        rate:    3,
        rateMin: 0,
        rateMax: 0,
    }
    giftlist[1] = g2
    // 3 虚拟券,相同的编码
    g3 := gift{
        id:      3,
        name:    "友善福",
        pic:     "友善福.jpg",
        link:    "",
        inuse:   true,
        rate:    2,
        rateMin: 0,
        rateMax: 0,
    }
    giftlist[2] = g3
    // 4 虚拟券,不相同的编码
    g4 := gift{
        id:      4,
        name:    "爱国福",
        pic:     "爱国福.jpg",
        link:    "",
        inuse:   true,
        rate:    1,
        rateMin: 0,
        rateMax: 0,
    }
    giftlist[3] = g4
    // 5 虚拟币
    g5 := gift{
        id:      5,
        name:    "敬业福",
        pic:     "敬业福.jpg",
        link:    "",
        inuse:   true,
        rate:    0,
        rateMin: 0,
        rateMax: 0,
    }
    giftlist[4] = g5
    return giftlist
}

// 根据概率,计算好的奖品信息列表
func giftRate(rate string) *[5]gift {
    giftlist := newGift()
    rates := strings.Split(rate, ",")
    ratesLen := len(rates)
    // 整理奖品数据,把rateMin,rateMax根据rate进行编排
    rateStart := 0
    for i, data := range giftlist {
        if !data.inuse {
            continue
        }
        grate := 0
        if i < ratesLen { // 避免数组越界
            grate, _ = strconv.Atoi(rates[i])
        }
        giftlist[i].rate = grate
        giftlist[i].rateMin = rateStart
        giftlist[i].rateMax = rateStart + grate
        if giftlist[i].rateMax >= rateMax {
            // 号码达到最大值,分配的范围重头再来
            giftlist[i].rateMax = rateMax
            rateStart = 0
        } else {
            rateStart += grate
        }
    }
    fmt.Printf("giftlist=%v\n", giftlist)
    return giftlist
}

// 初始化日志信息
func initLog() {
    f, _ := os.Create("/var/log/lottery_demo.log")
    logger = log.New(f, "", log.Ldate|log.Lmicroseconds)
}

func newApp() *iris.Application {
    app := iris.New()
    mvc.New(app.Party("/")).Handle(&lotteryController{})
    // 初始化日志信息
    initLog()
    return app
}

// 抽奖的控制器
type lotteryController struct {
    Ctx iris.Context
}

// GET http://localhost:8080/?rate=4,3,2,1,0
func (c *lotteryController) Get() string {
    rate := c.Ctx.URLParamDefault("rate", "4,3,2,1,0")
    giftlist := giftRate(rate)
    return fmt.Sprintf("%v\n", giftlist)
}

// GET http://localhost:8080/lucky?uid=1&rate=4,3,2,1,0
func (c *lotteryController) GetLucky() map[string]interface{} {
    uid, _ := c.Ctx.URLParamInt("uid")
    rate := c.Ctx.URLParamDefault("rate", "4,3,2,1,0")
    code := luckyCode()
    fmt.Printf("code=%v\n", code)
    ok := false
    result := make(map[string]interface{})
    result["success"] = ok
    giftlist := giftRate(rate)
    for _, data := range giftlist {
        if !data.inuse {
            continue
        }
        if data.rateMin <= int(code) && data.rateMax >= int(code) {
            // 中奖了,抽奖编码在奖品中奖编码范围内
            ok = true
            sendData := data.pic

            if ok {
                // 中奖后,成功得到奖品(发奖成功)
                // 生成中奖纪录
                saveLuckyData(uid, code, data.id, data.name, data.link, sendData)
                result["success"] = ok
                result["uid"] = uid
                result["id"] = data.id
                result["name"] = data.name
                result["link"] = data.link
                result["data"] = sendData
                break
            }
        }
    }

    return result
}

// 抽奖编码
func luckyCode() int32 {
    seed := time.Now().UnixNano()                                 // rand内部运算的随机数
    code := rand.New(rand.NewSource(seed)).Int31n(int32(rateMax)) // rand计算得到的随机数
    return code
}

// 记录用户的获奖记录
func saveLuckyData(uid int, code int32, id int, name, link, sendData string) {
    logger.Printf("lucky, uid=%d, code=%d, gift=%d, name=%s, link=%s, data=%s ", uid, code, id, name, link, sendData)
}

首页:


抽奖:


压力测试:

[root@localhost wrk]# > /var/log/lottery_demo.log 
[root@localhost wrk]# wc -l /var/log/lottery_demo.log 
0 /var/log/lottery_demo.log
[root@localhost wrk]# /usr/local/bin/wrk -t15 -c15 -d10 http://localhost:8080/lucky
Running 10s test @ http://localhost:8080/lucky
  15 threads and 15 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.73ms    2.38ms  25.83ms   83.99%
    Req/Sec   422.48     61.82   700.00     68.93%
  63603 requests in 10.10s, 13.83MB read
Requests/sec:   6297.95
Transfer/sec:      1.37MB
[root@localhost wrk]# /usr/local/bin/wrk -t15 -c15 -d10 http://localhost:8080/lucky
Running 10s test @ http://localhost:8080/lucky
  15 threads and 15 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.59ms    2.23ms  28.49ms   83.08%
    Req/Sec   440.23     58.14   673.00     69.73%
  66240 requests in 10.08s, 14.40MB read
Requests/sec:   6569.48
Transfer/sec:      1.43MB

发现qps比上一个抽奖低了一倍多,是因为每一次都要进入到抽奖里面的指针逻辑,开销比较大,而没有线程安全性问题是因为没有共享变量,也没有库存,操作的giftlist每次都是从内存中开辟出来的新的空间,然后返回的。

上一篇下一篇

猜你喜欢

热点阅读