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 单例模式


Lazy Loading:

type singleton struct {
}

// private
var instance *singleton

// public
func GetInstance() *singleton {
    if instance == nil {
        // not thread safe
        instance = &singleton{}
    }
    return instance
}

带锁:

type singleton struct {
}

var instance *singleton
var mu sync.Mutex

func GetInstance() *singleton {
    mu.Lock()
    defer mu.Unlock()
    if instance == nil {
        // unnecessary locking if instance already created
        instance = &singleton{}
    }
    return instance
}

带检查锁:

// <-- Not yet perfect. since it's not fully atomic
if instance == nil {
    mu.Lock()
    defer mu.Unlock()
    if instance == nil {
        instance = &singleton{}
    }
}
return instance

阅读全文

Go 打印函数执行时间


package main

import (
    "fmt"
    "time"
)

func timeCost(start time.Time) {
    terminal := time.Since(start)
    fmt.Println(terminal)
}

func main() {
    defer timeCost(time.Now())
    fmt.Println("start program")
    time.Sleep(5 * time.Second)
    fmt.Println("finish program")
}
阅读全文

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 convert "type []string" to string


package main

import (
    "fmt"
    "strings"
)

var naiveList string

func main() {
    naiveArray := []string{"a", "b", "c", "d", "e"}
    for _, v := range naiveArray {
        if naiveList == "" {
        naiveList = v
        } else {
        naiveList = strings.Join([]string{naiveList, v}, ",")
        }
    }
    fmt.Println(naiveList)
}
阅读全文

Go Redis 库 Redigo


https://github.com/garyburd/redigo/

引入库

import (
    "github.com/garyburd/redigo/redis"
)

查询数据

cli, cerr := redis.Dial("tcp", ip:port, redis.DialPassword(redisPasswd), redis.DialDatabase(1))
if cerr != nil {
    fmt.Println(cerr)
}
defer cli.Close()
// 查询 key
val, err := redis.String(cli.Do("GET", key))
if err != nil {
    fmt.Println(err)
}
return val

写入数据

cli, cerr := redis.Dial("tcp", ip:port, redis.DialPassword(redisPasswd), redis.DialDatabase(1))
if cerr != nil {
    fmt.Println(cerr)
}
defer cli.Close()
_, err := cli.Do("SET", key, value)
if err != nil {
    fmt.Println(err)
}
阅读全文

Go 轻量级 MySQL 库 go-sql-driver


https://github.com/go-sql-driver/mysql

引入库

import (
    "database/sql"

    _ "github.com/go-sql-driver/mysql"
)

查询数据

// 建立 MySQL 链接
db, err := sql.Open("mysql", "user:passwd@tcp(ip:port)/db")
if err != nil {
    fmt.Println(err)
}
defer db.Close()
// 执行 SQL
rows, rerr := db.Query(sqlInfo)
if rerr != nil {
    fmt.Println(rerr)
}
defer rows.Close()
// 获取 SQL 数据
for rows.Next() {
    var returnData string
    err := rows.Scan(&returnData)
    if err != nil {
        fmt.Println(err)
    }
    return returnData
}
return returnData

写入/更新数据

// 建立 MySQL 链接
db, err := sql.Open("mysql", "user:passwd@tcp(ip:port)/db")
if err != nil {
    fmt.Println(err)
}
defer db.Close()
// 执行 SQL
db.Exec(sqlInfo)
阅读全文

Go 语言小细节(四)


map 的容量
你可以在 map 创建时指定它的容量,但你无法在 map 上使用 cap() 函数。

package main
func main() {  
    m := make(map[string]int,99)
    cap(m)
}

匿名函数作用域陷阱

import (
    "fmt"
)

func main(){
    var msgs []func()
    array := []string{
        "1", "2", "3", "4",
    }
    for _, e := range array{
        msgs = append(msgs, func(){
            fmt.Println(e)
        })
    }
    for _, v := range msgs{
        v()
    }
}

阅读全文

Go 语言小细节(三)


在 for 语句的闭包中使用迭代变量会有问题
在 for 迭代过程中,迭代变量会一直保留,只是每次迭代值不一样。因此在 for 循环中在闭包里直接引用迭代变量,在执行时直接取迭代变量的值,而不是闭包所在迭代的变量值。如果闭包要取所在迭代变量的值,就需要 for 中定义一个变量来保存所在迭代的值,或者通过闭包函数传参。

package main

import (  
    "fmt"
    "time"
)

func forState1(){
    data := []string{"one","two","three"}

    for _,v := range data {
        go func() {
            fmt.Println(v)
        }()
    }
    time.Sleep(3 * time.Second)
    // three, three, three

    for _,v := range data {
        vcopy := v
        // 使用临时变量
        go func() {
            fmt.Println(vcopy)
        }()
    }
    time.Sleep(3 * time.Second)
    // one, two, three

    for _,v := range data {
        go func(in string) {
            fmt.Println(in)
        }(v)
    }
    time.Sleep(3 * time.Second)
    // one, two, three
}

func main() {  
    forState1()
}

阅读全文