iris 抽奖实例1

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

1. 简单实现抽奖

/**
 * curl http://localhost:8080/
 * curl --data="user=user1,user2" http://localhost:8080/import
 * curl http://localhost:8080/lucky
 */
package main

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

var userList []string

type lotteryController struct {
    Ctx iris.Context
}

func newApp() *iris.Application {
    app := iris.New()
    mvc.New(app.Party("/")).Handle(&lotteryController{})
    return app
}

func main()  {
    app := newApp()
    userList = []string{}

    app.Run(iris.Addr(":8080"))
}

func (c *lotteryController) Get() string {
    count := len(userList)
    return fmt.Sprintf("当前总共参加抽奖的用户数: %d\n", count)
}

func (c *lotteryController) PostImport() string  {
    strUsers := c.Ctx.FormValue("users")
    users := strings.Split(strUsers, ",")
    count1 := len(userList)
    for _, u := range users {
        u = strings.TrimSpace(u)
        if len(u) > 0 {
            userList = append(userList, u)
        }
    }
    count2 := len(userList)
    return fmt.Sprintf("当前总共参与抽奖的用户数: %d,成功导入的用户数:%d\n",
        count2, count2 - count1)
}

func (c *lotteryController) GetLucky() string {
    count := len(userList)
    if count > 1 {
        seed := time.Now().UnixNano()
        index := rand.New(rand.NewSource(seed)).Int31n(int32(count))
        user := userList[index]
        userList = append(userList[0:index], userList[index+1:]...)
        return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user , count-1)
    } else if count == 1 {
        user := userList[0]
        return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user , count-1)
    } else {
        return fmt.Sprintf("当前已经没有参与用户,请先通过 /import 导入用户\n")
    }
}

测试请求当前总共参加抽奖的用户数



测试请求导入用户



测试请求抽奖

2. 写个单元测试简单测试下并发

同目录下创建main_test.go文件,内容如下

package main

import (
    "fmt"
    "github.com/kataras/iris/v12/httptest"
    "sync"
    "testing"
)

func TestMVC(t *testing.T) {
    e := httptest.New(t, newApp())

    /**
     * WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait()
     * 用来控制计数器的数量。
     * Add(n) 把计数器设置为n ,Done() 每次把计数器-1 ,wait() 会阻塞代码的运行,直到计数器地值减为0。
     */
    var wg sync.WaitGroup
    e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参加抽奖的用户数: 0\n")

    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func(i int) {
            /**
             *  defer 语句会将其后面跟随的语句进行延迟处理,
             * 在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,
             * 也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
             */
            defer wg.Done()

            e.POST("/import").WithFormField("users", fmt.Sprintf("test_u%d", i)).Expect().Status(httptest.StatusOK)
        }(i)
    }

    wg.Wait()

    e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参加抽奖的用户数: 100\n")
    e.GET("/lucky").Expect().Status(httptest.StatusOK)
    e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("当前总共参加抽奖的用户数: 99\n")
}

执行程序:



发现存在线程安全性问题,没有导入100个用户的情况,因此需要优化下代码,为了实现线程安全,引入锁的使用,main.go的文件内容修改如下:

/**
 * curl http://localhost:8080/
 * curl --data="user=user1,user2" http://localhost:8080/import
 * curl http://localhost:8080/lucky
 */
package main

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

var userList []string
var mu sync.Mutex

type lotteryController struct {
    Ctx iris.Context
}

func newApp() *iris.Application {
    app := iris.New()
    mvc.New(app.Party("/")).Handle(&lotteryController{})
    return app
}

func main()  {
    app := newApp()
    userList = []string{}
    mu = sync.Mutex{}//初始化互斥锁

    app.Run(iris.Addr(":8080"))
}

func (c *lotteryController) Get() string {
    count := len(userList)
    return fmt.Sprintf("当前总共参加抽奖的用户数: %d\n", count)
}

func (c *lotteryController) PostImport() string  {
    strUsers := c.Ctx.FormValue("users")
    users := strings.Split(strUsers, ",")

    mu.Lock()
    defer mu.Unlock()

    count1 := len(userList)
    for _, u := range users {
        u = strings.TrimSpace(u)
        if len(u) > 0 {
            userList = append(userList, u)
        }
    }
    count2 := len(userList)
    return fmt.Sprintf("当前总共参与抽奖的用户数: %d,成功导入的用户数:%d\n",
        count2, count2 - count1)
}

func (c *lotteryController) GetLucky() string {
    mu.Lock()
    defer mu.Unlock()

    count := len(userList)
    if count > 1 {
        seed := time.Now().UnixNano()
        index := rand.New(rand.NewSource(seed)).Int31n(int32(count))
        user := userList[index]
        userList = append(userList[0:index], userList[index+1:]...)
        return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user , count-1)
    } else if count == 1 {
        user := userList[0]
        return fmt.Sprintf("当前中奖用户:%s, 剩余用户数:%d\n", user , count-1)
    } else {
        return fmt.Sprintf("当前已经没有参与用户,请先通过 /import 导入用户\n")
    }
}

其中对到导入和抽奖两个方法加上了互斥锁,因为这两个方法会对 userList 修改值,因此需要上锁
再次测试:


注:代码源自于慕课大佬视频

上一篇下一篇

猜你喜欢

热点阅读