当前位置:网站首页>Hello go (XIII). Go language common standard library III

Hello go (XIII). Go language common standard library III

2022-06-11 17:58:00 Tianshan old demon

One 、sync

1、sync brief introduction

sync Provides basic synchronization primitives , Such as sync.Mutex,sync.RWMutex,sync.Once,sync.Cond,sync.Waitgroup, except Once and WaitGroup Out of type , Most types are used by low-level libraries .Go In language , Do not communicate through shared memory , And to share memory through communication , adopt Channel And communication can better complete higher-level synchronization .

type Locker interface {
   Lock()
   Unlock()
}

Locker Two operation methods of lock are provided ,Lock、Unlock.

2、sync.Mutex

sync.Mutex It's a mutex , yes Locker An implementation of .

A mutex can only be locked by one at the same time goroutine lock , Other goroutine Will block until the mutex is unlocked ( Re contention for lock on mutex ).

sync.Mutex Use caution :

(1) Do not copy mutexes after first use .

(2) Unlocking an unlocked mutex will result in a runtime error .

Examples of use :

package main

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

var locker sync.Mutex

func mutexDemo() {
   var value int = 0
   for i := 0; i < 100; i++ {
      go func(i int) {
         locker.Lock()
         defer locker.Unlock()
         fmt.Printf("Goroutine %d : value: %d\n", i, value)
         value++
      }(i)
   }
}
func main() {
   mutexDemo()
   time.Sleep(time.Second)
}

3、sync.Pool

sync.Pool  The temporary object pool is used to store temporary objects , Store the used objects in the object pool , Take it out and reuse it when you need it , The purpose is to avoid creating the same object repeatedly GC Overburdened . If the object is no longer referenced by other variables , Stored temporary objects may be GC Recycle .

type Pool struct {
   //  Functions that create temporary objects 
   New func() interface{}
}

//  Store objects into the temporary object pool 
func (p *Pool) Put(x interface{})

//  Fetch objects from the temporary object pool 
func (p *Pool) Get() interface{}

from sync.Pool When the object is taken out of the , If Pool There are no objects in , Will return nil, But if you give Pool.New Field specifies a function ,Pool A new object will be created using the specified function to return .

sync.Pool It can be safely used in multiple goroutine In parallel , But it does not apply to all idle objects , Temporary objects that should be used to manage concurrent routine sharing , Instead of managing temporary objects in short-lived objects .

sync.Pool An example is as follows :

package main

import (
   "bytes"
   "io"
   "os"
   "sync"
   "time"
)



var bufPool = sync.Pool{
   New: func() interface{} {
      return new(bytes.Buffer)
   },
}

func Log(w io.Writer, key, val string) {
   //  Get temporary objects , If not, create it automatically 
   b := bufPool.Get().(*bytes.Buffer)
   b.Reset()
   b.WriteString(time.Now().Format(time.RFC3339))
   b.WriteByte(' ')
   b.WriteString(key)
   b.WriteByte('=')
   b.WriteString(val)
   w.Write(b.Bytes())
   //  Put the temporary object back to Pool in 
   bufPool.Put(b)
}

func main() {
   Log(os.Stdout, "key", "value")
}

// output:
// 2018-12-31T15:57:27+08:00 key=value

4、sync.Once

sync.Once You can make the function execute only once after multiple calls .

type Once struct {
   m    Mutex
   done uint32
}

func (o *Once) Do(f func())

use done To record the number of executions , Use a mutex m To ensure that it is executed only once . only one Do Method , Calls to perform .

utilize sync.Once The code to implement the singleton mode is as follows :

package Singleton

import (
   "sync"
)

type Singleton map[string]string

var (
   instance Singleton
   once sync.Once
)

func New() Singleton{
   once.Do(func() {
      instance = make(Singleton)
   })
   return instance
}

An example is as follows :

package main

import (
   "fmt"
   "DesignPattern/Singleton"
)

func main() {
   instance1 := Singleton.New()
   instance1["name"] = "Jack Bauer"
   instance2 := Singleton.New()
   fmt.Println("My name is", instance2["name"])
}
// output:
// My name is Jack Bauer

5、sync.RWMutex

sync.RWMutex Is a mutex for read / write operations , The biggest difference between read-write lock and mutex lock is that they can read and write separately 、 Write to lock . It is generally used in a large number of read operations 、 A small number of write operations .sync.RWMutex Four operation methods are provided :

func (rw *RWMutex) Lock()
func (rw *RWMutex) Unlock()

func (rw *RWMutex) RLock()
func (rw *RWMutex) RUnlock()

RLock Lock the read operation ,RUnlock Unlock the read lock ,Lock Lock the write operation ,Unlock Unlock the write lock .

sync.RWMutex The locking rules are as follows :

(1) There can only be one at a time goroutine Can get write lock .

(2) There can be any number of gorouinte Get read lock .

(3) At the same time, only write lock or read lock can exist ( Reading and writing are mutually exclusive ).

(4) When you have one goroutine Get a write lock , Others, whether read lock or write lock, will be blocked until write is unlocked ; When you have one goroutine Get read lock , Other read locks can still continue ; When there is one or more read locks , The write lock will wait until all the read locks are unlocked before the write lock can be performed .

sync.RWMutex Pay attention to the use of read-write locks :

(1) After first use , Do not duplicate read / write locks .

(2) Don't mix lock and unlock , Such as :Lock and RUnlock、RLock and Unlock. Unlocking the read-write lock without read lock or unlocking the read-write lock without write lock will cause runtime error .

Use sample code :

package main

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

var rw sync.RWMutex

func RWMutexDemo() {
   var value int = 0
   for i := 0; i < 10; i++ {
      go func(i int) {
         rw.Lock()
         defer rw.Unlock()
         fmt.Printf("Goroutine %d : Write value: %d\n", i, value)
         value++
      }(i)
      go func(i int) {
         rw.RLock()
         defer rw.RUnlock()
         fmt.Printf("Goroutine %d : Read value: %d\n", i, value)
      }(i)

   }
}
func main() {
   RWMutexDemo()
   time.Sleep(time.Minute)
}

6、sync.WaitGroup

sync.WaitGroup Used to wait for a group goroutine end .

sync.WaitGroup The operation method is as follows :

func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()

Add Used to add goroutine The number of .Done Perform a quantity reduction 1.Wait Used to wait for the end .

sync.WaitGroup An example is as follows :

package main

import (
   "fmt"
   "sync"
)

var wg sync.WaitGroup

func WaitGroupDemo() {
   var value int = 0
   for i := 0; i < 10; i++ {
      wg.Add(1)
      go func(i int) {
         defer wg.Done()
         fmt.Printf("Goroutine %d : Write value: %d\n", i, value)
         value++

      }(i)
      wg.Add(1)
      go func(i int) {
         defer wg.Done()
         fmt.Printf("Goroutine %d : Read value: %d\n", i, value)
      }(i)
   }
}

func main() {
   WaitGroupDemo()
   wg.Wait()
}

7、sync.Cond

sync.Cond Implement a conditional wait variable , I.e. waiting for or announcing the occurrence of the event goroutine Meeting point of .

func NewCond(l Locker) *Cond
func (c *Cond) Broadcast()
func (c *Cond) Signal()
func (c *Cond) Wait()

NewCond For use in accordance with Locker Create a conditional wait variable ,Wait Used to make a goroutine Wait for a notice ,Signal It is used to send a notification in a single time to make the waiting goroutine continue ,Broadcast Used to broadcast notifications to keep all waiting goroutine continue .

sync.Cond The conditional wait variable implements the producer - Examples of consumer patterns are as follows :

package main

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



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

var capacity = 10
var consumerNum = 5
var producerNum = 2

func Produce(out chan<- int) {
   for i := 0; i < producerNum; i++ {
      go func(nu int) {
         for {
            cond.L.Lock()
            for len(out) == capacity {
               fmt.Println("Capacity Full, stop Produce")
               cond.Wait()
            }
            num := rand.Intn(100)
            out <- num
            fmt.Printf("Producer %d produce: num %d\n", nu, num)
            cond.L.Unlock()
            cond.Signal()
            time.Sleep(time.Microsecond * 500)
         }
      }(i)
   }
}

func Consume(in <-chan int) {
   for i := 0; i < consumerNum; i++ {
      go func(nu int) {
         for {
            cond.L.Lock()
            for len(in) == 0 {
               fmt.Println("Capacity Empty, stop Consume")
               cond.Wait()
            }
            num := <-in
            fmt.Printf("Consumer %d: consume num %d\n", nu, num)
            cond.L.Unlock()
            time.Sleep(time.Second)
            cond.Signal()
         }
      }(i)
   }
}

func main() {
   rand.Seed(time.Now().UnixNano())

   quit := make(chan bool)
   ProductPool := make(chan int, capacity)

   Produce(ProductPool)
   Consume(ProductPool)

   <-quit
}

Two 、reflect

1、reflect brief introduction

In the field of Computer Science , Reflection refers to applications that are self describing and self controlling . Reflection uses some mechanism to describe its own behavior (self-representation) And monitoring (examination), And according to the state and result of their own behavior , Adjust or modify the state and related semantics of the behavior described by the application .

Each language has a different reflection model , And some languages do not support reflection .Golang Language passing reflect The package implements the reflection mechanism , Dynamically call methods and properties of objects at run time .

Go Variables in the language include (type, value) Two parts ,type Include static type and concrete type.static typ Is the type of encoding ( Such as int、string),concrete type yes runtime The type of .

Whether the type assertion can succeed , Depends on the of the variable concrete type, instead of static type. therefore , One reader Variable if it concrete type Realized write Method , It can also be asserted by type as writer.

Golang Specifies that the type of the type variable is static , The type is determined when the variable is created , therefore , Reflection is mainly related to Golang Of interface Type related (type yes concrete type).

stay Golang In the implementation of , Every interface Every variable has a (value, type) For actual values and types used to record variables .value Is the actual value of the variable ,type Is the actual type of the variable .interface Variables of type include 2 A pointer to the , A pointer to the type of value (concrete type), The other pointer points to the actual value (value).

2、reflect Interface

func TypeOf(i interface{}) Type

TypeOf The type used to dynamically obtain the value in the input parameter interface , If the interface is empty, return nil.

func ValueOf(i interface{}) Value

ValueOf Used to obtain the value of data in the input parameter interface , If the interface is empty, return 0.

reflect.ValueOf(interface) Get one relfect.Value Variable , Can pass relfect.Value Of itself Interface() Method to get the real content of the interface variable , You can then convert by type judgment , Convert to the original real type . The real type may be a known old type , It may also be an unknown original type .

For known legacy types :

package main

import (
   "fmt"
   "reflect"
)

func main() {

   var num float64 = 3.14
   value := reflect.ValueOf(num)
   pointer := reflect.ValueOf(&num)
   fmt.Println("value: ", value.Interface().(float64))
   fmt.Println("value: ", pointer.Interface().(*float64))
   fmt.Println("type: ", reflect.TypeOf(num))
}

// output:
// value:  3.14
// value:  0xc42001e0e8
// type:  float64

For unknown legacy types , You need to traverse to detect its Filed:

package main

import (
   "fmt"
   "reflect"
)

type Student struct {
   Name string
   ID   int
   Age  int
}

func (student Student) Print() {
   fmt.Printf("%s's ID is %d, %d years.", student.Name, student.ID, student.Age)
}

func handleFieldAndMethod(input interface{}) {
   inputType := reflect.TypeOf(input)
   fmt.Println("type: ", inputType.Name())
   inputValue := reflect.ValueOf(input)
   fmt.Println("value: ", inputValue)
   //  Get method field 
   // 1.  First get interface Of reflect.Type, And then through NumField Traversal 
   // 2.  Re pass reflect.Type Of Field Get its Field
   // 3.  Finally through Field Of Interface() Get the corresponding value
   for i := 0; i < inputType.NumField(); i++ {
      field := inputType.Field(i)
      value := inputValue.Field(i).Interface()
      fmt.Printf("%s %v %v\n", field.Name, field.Type, value)
   }
   //  Access method 
   // 1.  First get interface Of reflect.Type, And then through .NumMethod Traversal 
   for i := 0; i < inputType.NumMethod(); i++ {
      m := inputType.Method(i)
      fmt.Printf("%s: %v\n", m.Name, m.Type)
   }
}

func main() {

   bauer := Student{"Bauer", 1, 130}
   handleFieldAndMethod(bauer)
}

// output:
// type:  Student
// value:  {Bauer 1 130}
// Name string Bauer
// ID int 1
// Age int 130
// Print: func(main.Student)
func (v Value) MethodByName(name string) Value

MethodByName Returns a function value corresponding to reflect.Value The name of the method .

func (v Value) Call(in []Value) []Value

Call Method will eventually call the real method , The parameters must be consistent .

package main

import (
   "fmt"
   "reflect"
)

type Student struct {
   Name string
   ID   int
   Age  int
}

func (student Student) Print() {
   fmt.Printf("%s's ID is %d, %d years.", student.Name, student.ID, student.Age)
}

func CallMethod() {
   student := Student{"Bauer", 1, 20}
   value := reflect.ValueOf(student)
   methodValue := value.MethodByName("Print")
   //  For nonparametric functions 
   args := make([]reflect.Value, 0)
   methodValue.Call(args)
}

func main() {
   CallMethod()
}

// output:
// Print: func(main.Student)

3、 ... and 、runtime

1、runtime brief introduction

Go The language compiler produces native executable code , The executable code still runs in Go Of runtime in ,runtime Responsible for management including memory allocation 、 Garbage collection 、 Stack processing 、goroutine、channel、 section (slice)、map And reflection (reflection) etc. .

runtime And C The role of the standard library is the same for the cross platform of the language ,runtime Can run in Windows and Unix platform , Can run in Intel or ARM On the processor .Go The program comes with runtime,runtime Responsible for interacting with the underlying operating system .

2、runtime Common methods

runtime.Gosched()

Let the current goroutine Give up  cpu  So that others goroutine function , The current thread will not be suspended , Therefore, the current thread will continue to execute in the future .

func NumCPU() int

Get the logic of the current system CPU  Nuclear quantity

runtime.GOMAXPROCS(i int)

Set the maximum number of simultaneous  CPU

adopt runtime.GOMAXPROCS function , How applications set up logical processors in the runtime system during runtime P The largest number . Should be called at the earliest in the application . And the best settings P The maximum method is to run Go Set the environment variables of the operating program before the program GOMAXPROCS, Instead of calling... In a program runtime.GOMAXPROCS function .

No matter what the integer value passed to the function is , Runtime system P The maximum value will always be 1~256 Between .

runtime.Goexit()

Quit current  goroutine( but defer The statement will execute as usual )

runtime.Goexit After function is called , Will immediately invoke his Groution The operation of was terminated , But other Goroutine It won't be affected .runtime.Goexit The function is terminating the call to it Goroutine The... Will be executed before the operation of Groution Which has not been implemented in defer sentence .

runtime.NumGoroutine()

Get the total number of tasks being executed and queued

runtime.NumGoroutine Function after being called , Will return the in a specific state in the system Goroutine The number of . Here refers specifically to Grunnable\Gruning\Gsyscall\Gwaition. In these States Groutine That is, it is regarded as active or being scheduled .

Be careful : Where the garbage is collected Groutine If the state of is also within this range , Will also be included in the counter .

runtime.GOOS

Get the target operating system

func GOROOT() string

Get current GOROOT

3、cgo

CGO It's the realization of Go And C Ways to interoperate , Include Go transfer C and C transfer Go Two processes .Go call C A pseudo package that needs to be introduced into the program ,import “C” That is in Go Pseudo package used in .C The pseudo package will be CGO The tool captures , And do some code rewriting and pile file generation , It won't be Go The compiler sees .

Go Call in language C The procedure is as follows :

// Custom function call 
package main

/*
#include <stdio.h>
#include <stdlib.h>
void output(char *str) {
   printf("%s\n", str);
}
*/
import "C"
import "unsafe"

func main() {
   str := C.CString("hello cgo")
   C.output(str)
   C.free(unsafe.Pointer(str))
}

4、 Scheduler

every last Go The program comes with a runtime,runtime Responsible for interacting with the underlying operating system , There will be scheduler Yes goruntines To schedule .

Four 、plugin

1、plugin brief introduction

Golang Is a statically compiled language , At compile time, all referenced packages are loaded and packaged into the final executable program , Therefore, you cannot dynamically load other shared libraries at run time .Go 1.8 Start ,Go Language Linux and MacOS Version passed plugin Package provides a plug-in mechanism for loading shared libraries , Be able to dynamically load external functions at runtime .

2、plugin Common methods

type Plugin struct {
   pluginpath string
   err        string        // set if plugin failed to load
   loaded     chan struct{} // closed when loaded
   syms       map[string]interface{}
}

func Open(path string) (*Plugin, error)
func (p *Plugin) Lookup(symName string) (Symbol, error)

type Symbol interface{}

Open: According to the parameters path The provided plug-in path loads the plug-in , And return a pointer to the plug-in structure *Plugin.

Lookup: *Plugin The only way to , By name symName Find the corresponding variable or method in the plug-in , With Symbol Form return of . Any element found in the plug-in is preceded by Symbol form ( namely interface{}) return , The results need to be judged and transformed in the form of assertions , Get the type you need .

3、 Plug in compilation method

Go The language compiler uses -buildmode=plugin Markup compilation generates a plug-in ( Shared object library files ).Go The exported functions and variables in the package are exposed as ELF Symbol , have access to plugin Packages find and bind at run time ELF Symbol .

go build -buildmode=plugin -o xxxplugin.so xxxplugin.go

If you want to better control the plug-in version , Implement the hot update plug-in , You can register plug-ins automatically . When the new version of the plug-in is loaded , Automatically register the plug-in version number , The method of preferentially using new version plug-ins in the plug-in platform .

4、 Plug in usage example

Plug in writing HelloPlugin.go:

package main

import (
   "fmt"
)

func init() {
   fmt.Println("Hello")
}

func Hello() {
   fmt.Println("world")
}

Plug in compilation :

go build -buildmode=plugin -o HelloPlugin.so HelloPlugin.go

Plug in call main.go:

package main

import (
   "fmt"
   "plugin"
)

func main() {
   open, err := plugin.Open("./HelloPlugin.so")
   if err != nil {
      fmt.Println(err.Error())
   }
   symbol, err := open.Lookup("Hello")
   if err != nil {
      fmt.Println(err)
   }
   symbol.(func())()
}

Compile operation :

go run main.go

5、 Plug in programming

The plug-in manager implements :

package PluginManager

import "fmt"

//  Plug in container 
var Plugins map[string]Plugin

func init() {
   Plugins = make(map[string]Plugin)
}

type Plugin interface {
   Start()
}

//  Start all the plug-ins in this container 
func Start() {
   for name, plugin := range Plugins {
      go plugin.Start()
      fmt.Printf("%s Plugin Start.\n", name)
   }
}

//  After the plug-in is finished, it must be inserted into the container 
func Register(name string, plugin Plugin) {
   Plugins[name] = plugin
}

Plug-in implementation :

package HelloPlugin

import (
   "GoExample/Plugin/PluginManager"
   "fmt"
)

type HelloPlugin struct {
}

//  Register plug-ins when importing packages 
func init() {
   plugin := HelloPlugin{}
   PluginManager.Register("HelloPlugin", plugin)
}
func (this HelloPlugin) Start() {
   fmt.Println("This is HelloPlugin.")
}

The plug-in USES :

package main

import "GoExample/Plugin/PluginManager"
import _ "GoExample/Plugin/HelloPlugin"

func main() {
   PluginManager.Start()
}

// output:
// HelloPlugin Plugin Start.

5、 ... and 、signal

1、signal brief introduction

os/signal Packets can be used to process signals ,Notify Method to listen for a received signal ,Stop Method to cancel listening .

func Notify(c chan<- os.Signal, sig ...os.Signal)

Notify Function will send the process to the system Signal Forward to channel c, Which signals to forward are determined by variable parameters ,SIGKILL and SIGSTOP Cannot be intercepted and processed .

Parameters c Indicates the of the received signal channel, Subsequent parameters indicate setting the signal to be monitored , If it is not set, it means that all signals are monitored .

func Stop(c chan<- os.Signal)

Stop Method to cancel listening for all signals on the channel .

2、signal Example

package main

import (
   "fmt"
   "os"
   "os/signal"
   "syscall"
)

func main() {
   signalChannel := make(chan os.Signal, 1)
   done := make(chan bool, 1)
   //  monitor SIGINT、SIGTERM
   signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM)
   go func(ch chan os.Signal) {
      //  Received signal 
      channel := <-ch
      fmt.Printf("Received a signal: %s\n", channel)
      done <- true
   }(signalChannel)
   // signal.Stop(signalChannel)
   for {
      fmt.Println("Waiting signal.")
      <-done
      fmt.Println("Exiting.")
   }
}

原网站

版权声明
本文为[Tianshan old demon]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203011855416527.html