Go语言学习 Day05 Summary part1

1.Mutexes

In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple goroutines.

Container holds a map of counters; since we want to update it concurrently from multiple goroutines, we add a Mutex to synchronize access. Note that mutexes must not be copied, so if this struct is passed around, it should be done by pointer.

Lock the mutex before accessing counters; unlock it at the end of the function using a defer statement.

[maxwell@oracle-db-19c Day05]$ vim mutexes.go   
[maxwell@oracle-db-19c Day05]$ cat mutexes.go
package main

import (
     "fmt"
     "sync"
)

type Container struct{
    mu         sync.Mutex
    counters map[string]int
}


func (c *Container) inc(name string){


     c.mu.Lock()
     defer c.mu.Unlock()
     c.counters[name]++

}


func main(){
    c := Container{

        counters: map[string]int{"a":0, "b":0},
    }

    var wg sync.WaitGroup

    doIncrement := func(name string, n int){
        for i:= 0; i < n; i++ {
            c.inc(name)
        }
        wg.Done()

    }

    wg.Add(3)
    go doIncrement("a", 10000)
    go doIncrement("a", 10000)
    go doIncrement("b", 10000)

    wg.Wait()
    fmt.Println(c.counters)
}
[maxwell@oracle-db-19c Day05]$ go run mutexes.go
map[a:20000 b:10000]
[maxwell@oracle-db-19c Day05]$ 

2. Stateful Goroutines

In the previous example we used explicit locking with mutexes to synchronize access to shared state across multiple goroutines. Another option is to use the built-in synchronization features of goroutines and channels to achieve the same result. This channel-based approach aligns with Go’s ideas of sharing memory by communicating and having each piece of data owned by exactly 1 goroutine.

[maxwell@oracle-db-19c Day05]$ vim stateful_goroutines.go   
[maxwell@oracle-db-19c Day05]$ cat stateful_goroutines.go
package main

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

type readOp struct {
    key int
    resp chan int
}

type writeOp struct {
    key int
    val int
    resp chan bool
}

func main() {

    var readOps uint64
    var writeOps uint64

    reads := make(chan readOp)
    writes := make(chan writeOp)

    go func(){
        var state = make(map[int]int)
        for {
            select {
            case read := <-reads:
                read.resp <- state[read.key]
            case write := <-writes:
                state[write.key] = write.val
                write.resp <- true
            }
        }
    }()

    for r := 0; r < 100; r++ {
        go func(){
            for{
               read := readOp{
                   key: rand.Intn(5),
                   resp: make(chan int)}
               reads <- read
               <-read.resp
               atomic.AddUint64(&readOps, 1)
               time.Sleep(time.Millisecond)
            }
        }()
    }

    for w := 0; w < 10; w++ {
        go func(){
            for {
                write := writeOp{
                    key: rand.Intn(5),
                    val: rand.Intn(100),
                    resp: make(chan bool)}
                writes <- write
                <-write.resp
                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)
}
[maxwell@oracle-db-19c Day05]$ go run stateful_goroutines.go
readOps: 65503
writeOps 6550
[maxwell@oracle-db-19c Day05]$ 

3.Sorting

Go’s sort package implements sorting for builtins and user-defined types. We’ll look at sorting for builtins first.

Sort methods are specific to the builtin type; here’s an example for strings. Note that sorting is in-place, so it changes the given slice and doesn’t return a new one.

We can also use sort to check if a slice is already in sorted order.

[maxwell@oracle-db-19c Day05]$ vim sorting.go   
[maxwell@oracle-db-19c Day05]$ cat sorting.go   
package main

import (
     "fmt"
     "sort"
)

func main(){

    strs := []string{"c","a", "b"}
    sort.Strings(strs)
    fmt.Println("Strings: ", strs)

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

    s := sort.IntsAreSorted(ints)
    fmt.Println("Sorted: ", s)
}
[maxwell@oracle-db-19c Day05]$ go run sorting.go
Strings:  [a b c]
Ints:   [2 4 7]
Sorted:  true
[maxwell@oracle-db-19c Day05]$ 

4.Sorting by Functions

Sometimes we’ll want to sort a collection by something other than its natural order. For example, suppose we wanted to sort strings by their length instead of alphabetically. Here’s an example of custom sorts in Go.

In order to sort by a custom function in Go, we need a corresponding type. Here we’ve created a byLength type that is just an alias for the builtin []string type.

We implement sort.Interface - LenLess, and Swap - on our type so we can use the sort package’s generic Sort function. Len and Swap will usually be similar across types and Less will hold the actual custom sorting logic. In our case we want to sort in order of increasing string length, so we use len(s[i]) and len(s[j]) here.

With all of this in place, we can now implement our custom sort by converting the original fruits slice to byLength, and then use sort.Sort on that typed slice.

[maxwell@oracle-db-19c Day05]$ vim sorting_by_functions.go
[maxwell@oracle-db-19c Day05]$ cat sorting_by_functions.go
package main

import (
     "fmt"
     "sort"
)

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)
}
[maxwell@oracle-db-19c Day05]$ go run sorting_by_functions.go
[kiwi peach banana]
[maxwell@oracle-db-19c Day05]$ 

5.Panic

panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.

We’ll use panic throughout this site to check for unexpected errors. This is the only program on the site designed to panic.

A common use of panic is to abort if a function returns an error value that we don’t know how to (or want to) handle. Here’s an example of panicking if we get an unexpected error when creating a new file.

Running this program will cause it to panic, print an error message and goroutine traces, and exit with a non-zero status.

[maxwell@oracle-db-19c Day05]$ vim panic.go
[maxwell@oracle-db-19c Day05]$ cat panic.go 
package main

import "os"

func main(){
    panic("a problem")

    _,err := os.Create("/tmp/file")
    if err != nil {
        panic(err)
    }
}
[maxwell@oracle-db-19c Day05]$ go run panic.go
panic: a problem

goroutine 1 [running]:
main.main()
        /home/maxwell/projects/golang_projects/go_by_examples/Day05/panic.go:6 +0x27
exit status 2
[maxwell@oracle-db-19c Day05]$ 

你可能感兴趣的:(Golang,golang,开发语言,后端)