Two kinds of speed limiting methods for Golang concurrent programming

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Introduction

Golang provides goroutine fast implementation of concurrent programming, in the real world, if the code in Goroutine consumes a lot of resources (CPU, memory, bandwidth, etc.), we need to speed up the program to prevent Goroutine from exhausting the resources.
Take the following pseudo-code example to see how goroutine is dragging down a db. Assuming that the userlist length is 10000, the first query from the database is whether the user in the userlist exists in the database, the presence is ignored, and the creation does not exist.

//不使用goroutine,程序运行时间长,但数据库压力不大for _,v:=range userList {    user:=db.user.Get(v.ID)    if user==nil {        newUser:=user{ID:v.ID,UserName:v.UserName}        db.user.Insert(newUser)    }}//使用goroutine,程序运行时间短,但数据库可能被拖垮for _,v:=range userList {    u:=v    go func(){        user:=db.user.Get(u.ID)        if user==nil {            newUser:=user{ID:u.ID,UserName:u.UserName}            db.user.Insert(newUser)        }    }()}select{}

In the example, the DB receives 10,000 reads in 1 seconds, with a maximum of 10,000 write operations, and the normal DB server is difficult to support. For DB, you can tamper with the connection pool, control the speed of access to the DB, and here we discuss two common methods.

Programme I

At the speed limit, one scenario is to discard the request, that is, if the request is too fast, discard the incoming request directly.

Realize

The implementation logic is as follows:

package mainimport (    "sync"    "time")//LimitRate 限速type LimitRate struct {    rate     int    begin    time.Time    count    int    lock     sync.Mutex}//Limit Limitfunc (l *LimitRate) Limit() bool {    result := true    l.lock.Lock()    //达到每秒速率限制数量,检测记数时间是否大于1秒    //大于则速率在允许范围内,开始重新记数,返回true    //小于,则返回false,记数不变    if l.count == l.rate {        if time.Now().Sub(l.begin) >= time.Second {            //速度允许范围内,开始重新记数            l.begin = time.Now()            l.count = 0        } else {            result = false        }    } else {        //没有达到速率限制数量,记数加1        l.count++    }    l.lock.Unlock()    return result}//SetRate 设置每秒允许的请求数func (l *LimitRate) SetRate(r int) {    l.rate = r    l.begin = time.Now()}//GetRate 获取每秒允许的请求数func (l *LimitRate) GetRate() int {    return l.rate}

Test

Here is the test code:

package mainimport (    "fmt")func main() {    var wg sync.WaitGroup    var lr LimitRate    lr.SetRate(3)        for i:=0;i<10;i++{        wg.Add(1)            go func(){                if lr.Limit() {                    fmt.Println("Got it!")//显示3次Got it!                }                            wg.Done()            }()    }    wg.Wait()}

Run results

Got it!Got it!Got it!

Only 3 got it! are displayed, indicating that another 7 limit returns a false result. Speed limit success.

Programme II

At the speed limit, another scenario is to wait, that is, when the request is too fast, the subsequent arrival request waits for the previous request to complete before it can run. This scenario is similar to a queue.

Realize

//LimitRate 限速type LimitRate struct {    rate       int    interval   time.Duration    lastAction time.Time    lock       sync.Mutex}//Limit 限速package mainimport (    "sync"    "time")func (l *LimitRate) Limit() bool {    result := false    for {        l.lock.Lock()        //判断最后一次执行的时间与当前的时间间隔是否大于限速速率        if time.Now().Sub(l.lastAction) > l.interval {            l.lastAction = time.Now()                result = true            }        l.lock.Unlock()        if result {            return result        }        time.Sleep(l.interval)    }}//SetRate 设置Ratefunc (l *LimitRate) SetRate(r int) {    l.rate = r    l.interval = time.Microsecond * time.Duration(1000*1000/l.Rate)}//GetRate 获取Ratefunc (l *LimitRate) GetRate() int {    return l.rate }

Test

package mainimport (    "fmt"    "sync"    "time")func main() {    var wg sync.WaitGroup    var lr LimitRate    lr.SetRate(3)        b:=time.Now()    for i := 0; i < 10; i++ {        wg.Add(1)        go func() {            if lr.Limit() {                fmt.Println("Got it!")            }            wg.Done()        }()    }    wg.Wait()    fmt.Println(time.Since(b))}

Run results

Got it!Got it!Got it!Got it!Got it!Got it!Got it!Got it!Got it!Got it!3.004961704s

Unlike scenario one, it shows 10 got it! But the run time is 3.00496 seconds and no more than 3 times per second. Speed limit success.

Reform

Back in the original example, we added the speed limit function. It is important to note that in our example, the request is not discarded and can only be queued, so we use the speed-limiting method of scenario two.

var lr LimitRate//方案二//限制每秒运行20次,可以根据实际环境调整限速设置,或者由程序动态调整。lr.SetRate(20)//使用goroutine,程序运行时间短,但数据库可能被拖垮for _,v:=range userList {    u:=v    go func(){        lr.Limit()        user:=db.user.Get(u.ID)        if user==nil {            newUser:=user{ID:u.ID,UserName:u.UserName}            db.user.Insert(newUser)        }    }()}select{}

If you have a better solution welcome to the exchange and sharing.

Original content for the author, do not reprint without permission, thank you for your cooperation.

About the Author:
Jesse, currently working in Joygenio, is engaged in Golang language development and architecture design.
Products being developed and maintained: www.botposter.com

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.