Go 语言编程实例(四)

互斥体

在前面的例子中,我们看到了如何使用原子操作来管理简单的计数器状态。对于更复杂的状态,可以使用 互斥体 来安全地访问多个 goroutine 中的数据。

在这个例子中,状态(state)是一个映射。示例中的互斥将同步访问状态。我们将跟踪执行的读写操作数量。

这里启动 100 个 goroutine 来对状态执行重复读取,每个 goroutine 中每 ms 读取一次。对于每个读取,我们选择一个键来访问。Lock() 互斥体以确保对状态的独占访问,读取所选键的值, Unlock() 互斥体,并增加 readOps 计数。

我们还将启动 10 个 goroutine 来模拟写入,使用与读取相同的锁模式。

让 10 个 goroutine 在状态和互斥体上工作一秒钟。采集和报告最终操作计数。手机和报告最终操作计数。用最后的锁状态,显示它是如何结束了。

package main

import (
    "sync"
    "math/rand"
    "sync/atomic"
    "time"
    "fmt"
)

func main(){
    var state = make(map[int]int)

    var mutex = &sync.Mutex{}

    var readOps  uint64 = 0
    var writeOps uint64 = 0

    for r := 0 ; r < 100 ; r ++{
        go func() {
            total := 0
            for{
                key:= rand.Intn(5)
                mutex.Lock()
                total += state[key]
                mutex.Unlock()
                atomic.AddUint64(&readOps , 1)

                time.Sleep(time.Millisecond)
            }
        }()
    }

    for w:= 0 ; w < 10 ; w ++{
        go func() {
            for{
                key := rand.Intn(5)
                val := rand.Intn(100)
                mutex.Lock()
                state[key] = val
                mutex.Unlock()
                atomic.AddUint64(&writeOps,1)
                time.Sleep(time.Millisecond)
            }
        }()
    }

    time.Sleep(time.Second)

    readOpsFinal := atomic.LoadUint64(&readOps)
    fmt.Println("readops:",readOpsFinal)

    writeOpsFinal := atomic.LoadUint64(&writeOps)
    fmt.Println("writeops",writeOpsFinal)

    mutex.Lock()
    fmt.Println("state",state)
    mutex.Unlock()
}

Go排序实例

Go语言的 sort 包实现了内置和用户定义类型的排序。排序方法特定于内置类型,排序是一个就地排序,不会生成新的切片。

这里举例了一个 int 一个 string 类型的例子。

package main

import (
    "sort"
    "fmt"
)

func main(){
    // example for string
    strs := []string{"c","a","b"}
    sort.Strings(strs)

    fmt.Println("Strings:",strs)

    //example of sorting
    ints := []int{7,2,4}
    sort.Ints(ints)
    fmt.Println("Ints: ",ints)

    //使用 sort 检查是相关 slice 是否已经被排好序
    s := sort.IntsAreSorted(ints)
    fmt.Println("sorted: ",s)
    
}

Go自定义函数

有时候,我们希望通过使用自然排序意外的其他方式对集合进行排序。例如,假设我们想通过字符串长度进行排序,下面是Go语言中自定义排序的类型。

为了使用Go语言中的自定义函数进行排序,我们需要一个相应的类型。这里创建了一个 ByLength 类型,它只是内置 []string 类型的别名。

需要实现 sort.Interface – Len , Less , Swap 在这个类型上,所以可以使用 sort 包中的一般 Sort 函数。 Len 和 Swap 通常在类型之间是相似的, Less 保存实际的自定义排序逻辑。在这个例子中,要按照字符串长度的增加顺序排序,因此在这里使用 len(s[i]) 和 len(s[j])。

所有这些都到位后,现在可以通过将原始 fruits 切片转换为 ByLength 来实现自定义排序,然后对该类型切片使用 sort.Sort() 方法。

package main

import (
    "sort"
    "fmt"
)

//定义类型
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])
}


//正常调用方法
func main(){
    fruits := []string{"peach","banana","kiwi"}
    sort.Sort(ByLength(fruits))
    fmt.Println(fruits)
}

Go panic 错误处理实例

Panic 通常意味着失去出乎意料的错了。大多数情况下,使用他来正常运行时不应该出现的错误,或者不准备妥善处理。

在程序中可使用 Panic 来检查意外的错误。

如果一个函数返回一个我们不知道如何(或想要)处理的错误值,那么 Panic 的常见用法就是终止。这里有一个例子,如果在创建一个新文件时需要意外的错误。

运行此程序将导致程序出错,打印错误消息和 goroutine 跟踪,并退出非零状态。

package main

import "os"

func main(){

    panic("a problem")

    _,err := os.Create("./test.log")
    if err != nil{
        panic(err)
    }
}
    原文作者:爪爪熊
    原文地址: https://www.jianshu.com/p/fd4ff12f5783
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞