golang学习

golang通道实现生产者、消费者

package main

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

// 数据生产者
func producer(header string, channel chan<-string) {
	for {
		channel <- fmt.Sprintf("%s: %v", header, rand.Int31())
		time.Sleep(1*time.Second)
	}
}

// 数据消费者
func customer(channel <-chan string) {
	for {
		message := <-channel
		fmt.Println(message)
	}
}

func main() {
	channel := make(chan string)
	go producer("cat", channel)
	go producer("dog", channel)
	customer(channel)
}

go语言为任意类型添加方法

package main

import "fmt"

type MyInt int

func (m MyInt) IsZero() bool {
	return m == 0
}

func (m MyInt) Add(other int) int {
	return other + int(m)
}

func main() {
	var b MyInt
	fmt.Println(b.IsZero())
	b = 1
	fmt.Println(b.Add(2))
}

结构体内嵌–"继承"
// 结构体内嵌特性:
// 1)内嵌的结构体,外部结构体可以直接访问其成员变量。
// 2)内嵌结构体的字段名是它的类型名。

package main

import "fmt"

// 结构体内嵌
type A struct {
	ax, ay int
}

type B struct {
	A
	bx, by float32
}

func main() {
	b := B{A{1, 2}, 3.0, 4.0}
	fmt.Println(b.ax, b.ay, b.bx, b.by)
	fmt.Println(b.A)
}

结构体内嵌模拟类的继承

package main

import "fmt"

type Flying struct{}

func (f *Flying) Fly() {
	fmt.Println("can fly")
}

type Walkable struct {}

func (f *Walkable) Walk() {
	fmt.Println("can walk")
}

type Human struct {
	Walkable
}

type Bird struct {
	Walkable
	Flying
}

func main() {
	b := new(Bird)
	fmt.Println("Bird: ")
	b.Fly()
	b.Walk()
	h := new(Human)
	fmt.Println("Human: ")
	h.Walk()
}

//无缓冲通道模拟两个协程间的网球比赛

package main

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

// 利用无缓冲通道模拟两个协程间的比赛
var wg sync.WaitGroup

func init() {
	rand.Seed(time.Now().UnixNano())
}

// player 模拟一个选手在打网球
func player(name string, court chan int) {
	// 在函数退出时调用Done来通知main函数工作已经完成
	defer wg.Done()

	for {
		ball, ok := <- court
		if !ok {
			fmt.Printf("player %s win\n", name)
			return
		}
		// 随机数,判断选手是否击球
		n := rand.Intn(100)
		if n%13 == 0 {
			fmt.Printf("player %s missed\n", name)
			close(court)
			return
		}
		// 显示击球数,并将击球数加1
		fmt.Printf("player %s hit %d \n", name, ball)
		ball++
		// 将球打向对手
		court <- ball
	}
}

func main() {
	// 无缓冲通道
	court := make(chan int)
	wg.Add(2)
	// 启动两个选手
	go player("Nadal", court)
	go player("Djokovic", court)
	// 发球
	court <- 1
	// 等待游戏结束
	wg.Wait()
}

// channel超时机制

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	quit := make(chan bool)
	// 新开一个协程
	go func() {
		for {
			select {
			case num := <-ch:
				fmt.Println("num = ", num)
			case <- time.After(3 * time.Second):
				fmt.Println("超时")
				quit <- true

			}
		}
	}()

	for i := 0; i < 5; i++ {
		ch <- i
		time.Sleep(time.Second)
	}
	<- quit
	fmt.Println("程序结束")
}

失控的goroutine

package main

import (
	"fmt"
	"runtime"
)

func consumer(ch chan int) {
	// 无限获取数据的循环
	for {
		data := <-ch
		fmt.Println(data)
	}
}

func main() {
	// 创建一个传递数据用的通道
	ch := make(chan int)
	for {
		var dummy string
		// 获取输入,模拟进程持续进行
		fmt.Scan(&dummy)
		go consumer(ch)
		// 输出当前的goroutine数量
		fmt.Println("num of goroutines:", runtime.NumGoroutine())
	}
}

go变量生命周期和逃逸分析

堆(heap):堆是用于存放进程执行中被动态分配的内存段。它的大小并不固定,可动态扩张或缩减。当进程调用 malloc 等函数分配内存时,新分配的内存就被动态加入到堆上(堆被扩张)。当利用 free 等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减);

栈(stack):栈又称堆栈, 用来存放程序暂时创建的局部变量,也就是我们函数的大括号{ }中定义的局部变量。

package main

var global *int

func f() {
	var x int
	x = 1
	global = &x
}
func g() {
	y := new(int)
	*y = 1
}
func main() {
	f()
	g()
}
golang变量逃逸分析
go run -gcflags "-m -l" main.go
使用 go run 运行程序时,-gcflags 参数是编译参数。其中 -m 表示进行内存分配分析,-l 表示避免程序内联,也就是避免进行程序优化。
上述代码中,函数 f 里的变量 x 必须在堆上分配,因为它在函数退出后依然可以通过包一级的 global 变量找到,虽然它是在函数内部定义的。用Go语言的术语说,这个局部变量 x 从函数 f 中逃逸了。
相反,当函数 g 返回时,变量 *y 不再被使用,也就是说可以马上被回收的。因此,*y 并没有从函数 g 中逃逸,编译器可以选择在栈上分配 *y 的存储空间,也可以选择在堆上分配,然后由Go语言的 GC(垃圾回收机制)回收这个变量的内存空间。
在实际的开发中,并不需要刻意的实现变量的逃逸行为,因为逃逸的变量需要额外分配内存,同时对性能的优化可能会产生细微的影响。

golang中的nil(空值/零值)

nil 是Go语言中一个预定义好的标识符,nil 是 map、slice、pointer、channel、func、interface 的零值。

package main

import "fmt"

func main() {
	var m map[int]string
	var ptr *int
	var c chan int
	var sl []int
	var f func()
	var i interface{}
	fmt.Printf("%#v\n", m)
	fmt.Printf("%#v\n", ptr)
	fmt.Printf("%#v\n", c)
	fmt.Printf("%#v\n", sl)
	fmt.Printf("%#v\n", f)
	fmt.Printf("%#v\n", i)
}

//map[int]string(nil)
//(*int)(nil)
//(chan int)(nil)
//[]int(nil)
//(func())(nil)
//<nil>

golang 指针类型的接收器

// 指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的this或者self。
// 由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。

package main

import "fmt"

// 定义属性结构
type Property struct {
	value int
}
// 设置属性值
func (p *Property) SetValue(v int) {
	p.value = v
}
// 取属性值
func (p *Property) Value() int {
	return p.value
}
func main() {
	// 实例化属性
	p := new(Property)
	p.SetValue(100)
	fmt.Println(p.value)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值