golang高级部分

简介: 一、golang之OOP(orient object programming)  在函数声明时, 在其名字之前放上一个变量, 即是一个方法。 这个附加的参数会将该函数附加到这种类型上, 即相当于为这种类型定义了一个独占的方法。

一、golang之OOP(orient object programming)

  在函数声明时, 在其名字之前放上一个变量, 即是一个方法。 这个附加的参数会将该函数附加到这种类型上, 即相当于为这种类型定义了一个独占的方法。(c++中称成员函数)

二、Goroutine和Channels

  在golang中,每一个并发的执行单元叫做一个goroutine;而channel则是它们之间的通信机制,它可以让一个goroutine通过channel给另一个goroutine发送消息;需要注意的是,每个channel都有一个特殊的类型;

  ch := make(chan int)

  close(ch)  //关闭channel

  2.1 无buffer channel

    ch := make(chan int)  or   ch := make(chan int , 0)

    一个基于无缓存Channels的发送操作将导致发送者goroutine阻塞, 直到另一个goroutine在相同的Channels上执行接收操作, 当发送的值通过Channels成功传输之后, 两个goroutine可以继续执行后面的语句。 反之, 如果接收操作先发生, 那么接收者goroutine也将阻塞, 直

  到有另一个goroutine在相同的Channels上执行发送操作。

    基于无缓存Channels的发送和接收操作将导致两个goroutine做一次同步操作。 因为这个原因, 无缓存Channels有时候也被称为同步Channels。 当通过一个无缓存Channels发送数据时, 接收者收到数据发生在唤醒发送者goroutine之前;

  2.2 单方向的channel

    类型 chan<- int 表示一个只发送int的channel, 只能发送不能接收。 相反, 类型 <-chan int 表示一个只接收int的channel, 只能接收不能发送。 ( 箭头 <- 和关键字chan的相对位置表明了channel的方向。 ) 这种限制将在编译期检测。 

1  12 // out 只发 channel
2  13 // in 只收channel
3  14 func squares(out chan<- int, in <-chan int) {
4  15     for v := range in {
5  16         out <- v * v
6  17     }
7  18     close(out)
8  19 }

  2.3 带buffer的channel

    ch = make(chan string, 3)

    向缓存Channel的发送操作就是向内部缓存队列的尾部插入元素, 接收操作则是从队列的头部删除元素。 如果内部缓存队列是满的, 那么发送操作将阻塞直到因另一个goroutine执行接收操作而释放了新的队列空间。 相反, 如果channel是空的, 接收操作将阻塞直到有另一个

  goroutine执行发送操作而向队列插入元素。

    获取channel的容量:cap(ch)     获取channel数据的长度:len(ch)

三、select多路复用

 1 package main
 2 
 3 import (
 4     "fmt"
 5     //"time"
 6 )
 7 
 8 /*
 9 select {
10 case <-ch1:
11     // ...
12 case <-ch2:
13     // ...
14 case <-ch3:
15     // ...
16 default:
17     // ...
18 }
19 */
20 
21 func main() {
22     j := make(chan int, 1)
23     //tick := time.Tick(1 * time.Second)
24     for down := 10; down > 0; down-- {
25         fmt.Println("down to here")
26         select {
27         case x := <-j:
28             fmt.Println(x)
29         case j <- down:
30             fmt.Println("put to j")
31         }   
32     }   
33 }

一、并发

  一般情况下,我们没法知道分别位于两个goroutine事件x和y的执行顺序,x是在y之前还是之后还是同时发生是没法判断的。 当我们能够没有办法明确地确认一个事件是在另一个事件的前面或者后面发生的话, 就说明x和y这两个事件是并发的。

  如何避免竞争?

    由于其它的goroutine不能够直接访问变量, 它们只能使用一个channel来发送给指定的goroutine请求来查询更新变量。 这也就是Go的口头禅“不要使用共享数据来通信;使用通信来共享数据”。 一个提供对一个指定的变量通过cahnnel来请求

  的goroutine叫做这个变量的监控(monitor)goroutine。

二、互斥  

  互斥原型实现:

 1 var (
 2     sema    = make(chan struct{}, 1)
 3     balance int 
 4 )
 5 
 6 func Add(amount int) {
 7     sema <- struct{}{}
 8     balance = balance + amount
 9     <-sema
10 }
11 
12 func Get() int {
13     sema <- struct{}{}
14     b := balance
15     <-sema
16 }
17 
18 import "sync"
19 var (
20     mu sync.Mutex
21     balance int
22 )          
23 func Add(amount int){
24     mu.Lock()
25     balance = balance + amount 
26     mu.Unlock()
27 }  
28 
29 func Get() int {
30     mu.Lock()
31     b := balance
32     mu.Unlock()
33 }

 

   func Get() int {

    mu.Lock()

    defer mu.Unlock()

    b := balance 

    return b

  }

 2.1 读写锁

   var rwmu sync.RWMutex              ----用于多度少写

   rwmu.Rlock() / rwmu.RUnlock()   ----读锁定,此时只能进行读操作

   rwmu.Lock() / rwmu.Unlock()      ----读写锁定

 2.2 sync.Once初始化
 1 /*
 2  sync.Once。 概念上来讲,
 3  一次性的初始化需要一个互斥量mutex和一个boolean变量来记录初始化是不是已经完成了;
 4  互斥量用来保护boolean变量和客户端数据结构。 Do这个唯一的方法需要接收初始化函数作为
 5  其参数。
 6 */
 7 var loadIconsOnce sync.Once
 8 var icons map[string]int
 9 func loadIcons() {
10      icons["first"] = 1
11      icons["second"] = 2
12      icons["thrid"]     = 3   
13 }
14 
15 func Icon(name string) int {
16     loadIconsOnce.Do(loadIcons)
17     return icons[name]
18 }

   2.3 sync.WaitGroup

   先说说WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成。这里要注意一下,他们的执行结果是没有顺序的,调度器不能保证多个 goroutine 执行次序,且进程退出时不会等待它们结束。

  WaitGroup总共有三个方法:Add(delta int),Done(),Wait()。简单的说一下这三个方法的作用。

Add:添加或者减少等待goroutine的数量

Done:相当于Add(-1)

Wait:执行阻塞,直到所有的WaitGroup数量变成0

  如:

    golang中的同步是通过sync.WaitGroup来实现的.WaitGroup的功能:它实现了一个类似队列的结构,可以一直向队列中添加任务,当任务完成后便从队列中删除,如果队列中的任务没有完全完成,可以通过Wait()函数来出发阻塞,防止程序继续进行,直到所有的队列任务都完成为止.

  WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,而不需要sleep一个固定的时间来等待.但是其缺点是无法指定固定的goroutine数目.可能通过使用channel解决此问题。  

相关文章
|
Go
Golang 语言函数的高级使用方式
Golang 语言函数的高级使用方式
49 0
|
算法 Java 测试技术
100天精通Golang(基础入门篇)——第20天:Golang 接口 深度解析☞从基础到高级
100天精通Golang(基础入门篇)——第20天:Golang 接口 深度解析☞从基础到高级
60 0
|
存储 Java 编译器
Golang可能会踩的58个坑之高级篇
Golang可能会踩的58个坑之高级篇
139 0
|
JSON 监控 Go
【Golang 快速入门】高级语法:反射 + 并发
Golang 进阶 反射 变量内置 Pair 结构 reflect 结构体标签 并发知识 基础知识 早期调度器的处理 GMP 模型 调度器的设计策略 并发编程 goroutine channel 无缓冲的 channel 有缓冲的 channel 关闭 channel channel 与 range channel 与 select
280 0
【Golang 快速入门】高级语法:反射 + 并发
|
13天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
33 2
|
11天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
21 2
|
11天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
24 2
|
1天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
1天前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
12 3
|
1天前
|
测试技术 Go 索引
go语言通过 for 循环遍历
go语言通过 for 循环遍历
10 3