go example之旅(下)

Introduce

这是来自于go by example的例子,花了几天的时间写完了这些例子,感觉对我的帮助很大,对于初学者来说,我的建议还是先找本go的书从头到尾看一下,然后再来看这些例子,每个例子都手敲一遍,对你的帮助还是很大的。在敲这些例子的过程中,有一些疑问,也有一些知识的扩充,因此总结了本文。

time和channel

golang的time package带有定时器的功能,而定时器和channel完美融合,创建一个定时器会返回一个channel,在定时器到期之前读这个channel是阻塞的,直到定时时间到达这个channel就会变成可读的。

func main() {
    //创建了一个定时器,2秒后会发送事件到timer1.C channel
    timer1 := time.NewTimer(time.Second * 2)

    //等待定时器到期
    data := <-timer1.C          //接收到的数据 2016-07-16 15:24:19.337701998 +0800 CST
    fmt.Println("Timer 1 expired")
    fmt.Println("Timer 1 expired",data)
    timer2 := time.NewTimer(time.Second)
    go func() {
        <- timer2.C
        fmt.Println("Timer 2 expired")
    }()

    //关闭定时器
    stop2 := timer2.Stop()
    if stop2 {
        fmt.Println("Timer 2 stopped")
    }
}

time package除了具有定时器的功能外,还有一个Ticker,Ticker同样也是和channel完美融合的一个功能,创建一个Ticker会返回channel
通过range这个channel。来表示每次interval的到来。再结合go的协程就很容易实现一个定时任务的功能。

func main() {
    //创建了定时器,每time.Millisecond * 500就产生事件,发送到chnanel
    ticker := time.NewTicker(time.Millisecond * 500)
    go func() {
        for t := range ticker.C {
            fmt.Println("Tick at",t)
        }
    }()
    //睡上一段事件,然后关闭
    time.Sleep(time.Millisecond * 1600)
    ticker.Stop()
    fmt.Println("Ticker stopped")
}

goroutines和work pool

goroutines结合channel很容易就可以实现一个work pool,开上N个goroutines,然后这N个goroutines共同去读channel,读到channel
就去执行相应的工作,然后结果通过另外一个channel传出来即可,模型很简单。用go实现起来还是很容易的。

func worker(id int,jobs <-chan int,result chan<- int) {
    for j := range jobs {
        fmt.Println("worker",id,"processing job",j)
        time.Sleep(time.Second)
        result <- j * 2
    }
}

func main() {
    jobs := make(chan int,100)
    results := make(chan int,100)
    //启动三个worker
    for w := 1; w <= 3; w++ {
        go worker(w,jobs,results)
    }
    //循环9次,发送任务
    for j := 1; j <= 9;j++ {
        jobs <- j
    }
    close(jobs)
    //循环得到结果
    for a := 1; a <= 9; a++ {
        <-results
    }
}

rate limiting与channel

限速这是一个用于控制资源利用率和保证服务质量的一种机制,golang通过goroutines,channel还有tickers优雅的支持了这个机制。比如处理web请求的限速,每接收一个请求就先读取一个tick,这个tick每隔固定时间才可读,这样就可以实现限速的功能。

func main() {
    requests := make(chan int,5)
    //发送五条消息
    for i := 1; i <= 5;i++ {
        requests <- i
    }

    close(requests)
    //创建了定时器,然后遍历channel,打印信息
    limiter := time.Tick(time.Millisecond * 200)
    for req := range requests {
        <-limiter   //每隔time.Millisecond * 200,起到了限速的作用
        fmt.Println("requests",req,time.Now())
    }

}

但是上面的限速存在一个问题,就是并发数只有1,如果可以在拥有固定的并发数的情况下限速呢?,这就需要借助channel的buffer功能了。上面的time.Tick返回的channel是没有buffer的,所以一次只能处理一个请求,如果这个channel是有buffer的,比如这个buffer的大小是N那么可以同时并发接收N个请求,想处理第N+1个请求就需要等待固定时间才可以。

func main() {
    //创建了另外一个time.Time类似的channel
    burstyLimiter := make(chan time.Time,3)
    //发送三个
    for i := 0; i < 3; i++ {
        burstyLimiter <- time.Now()
    }

    go func() {
        for t := range time.Tick(time.Millisecond * 200) {
            burstyLimiter <- t //每200 * time.Millisecond 就发送一个事件到burstyLimiter
        }
    }()


    burstyRequests := make(chan int,5)
    for i := 1; i <= 5; i++ {
        burstyRequests <- i //发送五个数据
    }
    close(burstyRequests)
    for req := range burstyRequests { //现在开始限速读取
        <-burstyLimiter//在读前三个的时候是不会阻塞的,直到读取第四个的 时候才开始通过Limiter限速
        fmt.Println("request",req,time.Now())
    }
}

自定义sort和Interface

golang的sort package自带排序的功能,但是如果要对用户自己定义的数据结构进行排序这就不好半了,在C++中要求用户对关系运算符重载即可在golang中则需要和interface完美融合,只要用户实现Len,Less,Swap三个接口即可,就是这么简单。

package main

import "fmt"
import "sort"

//string slice的别名,给这个别名struct 添加方法
type ByLength []string

func (s ByLength) Len() int {
    return len(s)
}

func (s ByLength) Swap(i,j int) {
    s[i],s[j] = s[j],s[i]
}

func (s ByLength) Less(i,j int) bool {
    return len(s[i]) < len(s[j])
}

//sort接口需要实现 Swap Less和len即可
func main() {
    fruits := []string{"peach","banana","kiwi"}
    sort.Sort(ByLength(fruits))
    fmt.Println(fruits)
}

signal和channel

golang再一次将unix上的signals和channel结合了起来,unix上通过给信号注册处理函数来完成信号处理,在golang中,通过把信号和channel关联起来,当有信号到来channel就可读了。返回的结果就是signal的号码。

import "fmt"
import "os"
import "os/signal"
import "syscall"

func main() {
    //os.Signal类型的chn
    sigs := make(chan os.Signal,1)
    done := make(chan bool,1)
    //通过Norify来注册信号,
    signal.Notify(sigs,syscall.SIGINT,syscall.SIGTERM)  //将SIGINT和SIGTERM和sigs channel结合起来

    //协成来收集信号,然后发送done chan来表示完成
    go func() {
        sig :=  <-sigs
        fmt.Println()
        fmt.Println(sig)
        done <- true
    }()

    fmt.Println("awaiting signal")
    <-done
    fmt.Println("exiting")
}
Sure! Here's an example of how to use go-plugin: First, you need to create a plugin. Here's an example plugin called "example_plugin.go": ``` package main import "fmt" type ExamplePlugin struct{} func (p *ExamplePlugin) SayHello() { fmt.Println("Hello from ExamplePlugin!") } var Plugin ExamplePlugin ``` This plugin defines a type called "ExamplePlugin" with a single method called "SayHello". When this method is called, it prints "Hello from ExamplePlugin!" to the console. Next, you need to create a host program that loads the plugin. Here's an example host program called "example_host.go": ``` package main import ( "fmt" "log" "github.com/hashicorp/go-plugin" ) func main() { pluginMap := map[string]plugin.Plugin{ "example_plugin": &ExamplePlugin{}, } client := plugin.NewClient(&plugin.ClientConfig{ HandshakeConfig: plugin.HandshakeConfig{ ProtocolVersion: 1, MagicCookieKey: "EXAMPLE_PLUGIN", MagicCookieValue: "1234", }, Plugins: pluginMap, }) defer client.Kill() raw, err := client.Dispense("example_plugin") if err != nil { log.Fatal(err) } examplePlugin, ok := raw.(*ExamplePlugin) if !ok { log.Fatal("Failed to cast plugin to ExamplePlugin") } examplePlugin.SayHello() } ``` This host program creates a plugin map that maps the name "example_plugin" to an instance of the ExamplePlugin type defined in the plugin. It then creates a client that connects to the plugin using the HandshakeConfig and plugin map, and retrieves an instance of the ExamplePlugin type using the client's Dispense function. Finally, it calls the SayHello method on the ExamplePlugin instance. To run this example, you would first need to build the plugin by running "go build -buildmode=plugin example_plugin.go". Then you would run the host program by running "go run example_host.go". This should output "Hello from ExamplePlugin!" to the console.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值