美文网首页
iris 抽奖实例1

iris 抽奖实例1

作者: 码农工号9527 | 来源:发表于2021-08-05 19:54 被阅读0次

    1. 简单实现抽奖

    • 安装并创建好iris测试项目
      在测试项目目录下创建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"
        "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 修改值,因此需要上锁
    再次测试:


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

    相关文章

      网友评论

          本文标题:iris 抽奖实例1

          本文链接:https://www.haomeiwen.com/subject/ratvvltx.html