Go cond 锁定期唤醒锁


package main

import (
    "fmt"
    "sync"
    "time"
)

var locker = new(sync.Mutex)
var cond = sync.NewCond(locker)

func test(x int) {
    // 获取锁
    cond.L.Lock()
    // 等待通知  暂时阻塞
    cond.Wait()
    fmt.Println(x)
    time.Sleep(time.Second * 1)
    // 释放锁
    cond.L.Unlock()
}
func main() {
    for i := 0; i < 40; i++ {
        go test(i)
    }
    fmt.Println("start all")
    time.Sleep(time.Second * 3)
    fmt.Println("broadcast")
    // 下发一个通知给已经获取锁的goroutine
    cond.Signal()
    time.Sleep(time.Second * 3)
    // 3秒之后 下发一个通知给已经获取锁的goroutine
    cond.Signal()
    time.Sleep(time.Second * 3)
    // 3秒之后 下发广播给所有等待的goroutine
    cond.Broadcast()
    time.Sleep(time.Second * 60)
}
阅读全文

Go 竞争检测


工作原理:
竞争检测器集成在 Go 工具链中。当使用了 -race 作为命令行参数后,编译器会插桩代码,使得所有代码在访问内存时,会记录访问时间和方法。同时运行时库会观察对共享变量的未同步访问。当这种竞争行为被检测到,就会输出一个警告信息。由于设计原因,竞争检测器只有在被运行的代码触发时,才能检测到竞争条件,因此在现实的负载条件下运行是非常重要的。但是由于代码插桩,程序会使用10倍的 CPU 和内存,所以总是运行插桩后的程序是不现实的。矛盾的解决方法之一就是使用插桩后的程序来运行测试。负载测试和集成测试是好的候选,因为它们倾向于检验代码的并发部分。另外的方法是将单个插桩后的程序布置到运行服务器组成的池中,并且给予生产环境的负载。

// 测试包
go test -race mypkg
// 编译和运行程序
go run -race mysrc.go
// 构建程序
go build -race mycmd
// 安装程序
go install -race mypkg
阅读全文

Go 中如何阻塞等待所有 goroutines 都完成


方案一:

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

// 定义一个同步等待的组
var wg sync.WaitGroup

// 定义一个Printer函数用于并发
func Printer(a int) {
    time.Sleep(2000 * time.Millisecond)
    fmt.Printf("i am %d\n", a)
    defer wg.Done()
}

func main() {
    // 获取cpu个数
    maxProcs := runtime.NumCPU()
    // 限制同时运行的goroutines数量
    runtime.GOMAXPROCS(maxProcs)
    for i := 0; i < 10; i++ {
        //为同步等待组增加一个成员
        wg.Add(1)
        //并发一个goroutine
        go Printer(i)
    }
    // 阻塞等待所有组内成员都执行完毕退栈
    wg.Wait()
    fmt.Println("WE DONE!!!")
}

阅读全文

Go 处理 HTTP 请求


引入包

import (
    "net/http"
)

具体实现

// HTTPGet compatible http & https
func HTTPGet(reqURL string) []byte {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    c := &http.Client{
        Transport: tr,
        Timeout:   30 * time.Second,
    }
    res, err := c.Get(reqURL)
    if err != nil {
        fmt.Println(err)
    }
    body, _ := ioutil.ReadAll(res.Body)
    res.Body.Close()
    responeDate := make(map[string]interface{})
    json.Unmarshal([]byte(string(body)), &responeDate)
    return responeDate
}

// HTTPPost is post func
func HTTPPost(reqURL, reqData string) map[string]interface{} {
    req, _ := http.NewRequest("POST", reqURL, strings.NewReader(reqData))
    req.Header.Set("Content-Type", "application/json")
    c := &http.Client{
        Timeout: 9 * time.Second,
    }
    res, err := c.Do(req)
    if err != nil {
        fmt.Println(err)
        return nil
    }
    body, _ := ioutil.ReadAll(res.Body)
    res.Body.Close()
    responeDate := make(map[string]interface{})
    json.Unmarshal([]byte(string(body)), &responeDate)
    return responeDate
}

// HTTPPut is post func
func HTTPPut(reqURL, reqData string) map[string]interface{} {
    req, _ := http.NewRequest("PUT", reqURL, strings.NewReader(reqData))
    req.Header.Set("Content-Type", "application/json")
    c := &http.Client{
        Timeout: 9 * time.Second,
    }
    res, err := c.Do(req)
    if err != nil {
        fmt.Println(err)
        return nil
    }
    body, _ := ioutil.ReadAll(res.Body)
    res.Body.Close()
    responeDate := make(map[string]interface{})
    json.Unmarshal([]byte(string(body)), &responeDate)
    return responeDate
}

// HTTPDelete is delete func
func HTTPDelete(reqURL, reqData string) map[string]interface{} {
    req, _ := http.NewRequest("DELETE", reqURL, strings.NewReader(reqData))
    req.Header.Set("Content-Type", "application/json")
    c := &http.Client{
        Timeout: 9 * time.Second,
    }
    res, err := c.Do(req)
    if err != nil {
        fmt.Println(err)
        return nil
    }
    body, _ := ioutil.ReadAll(res.Body)
    res.Body.Close()
    responeDate := make(map[string]interface{})
    json.Unmarshal([]byte(string(body)), &responeDate)
    return responeDate
}
阅读全文