Golang|panic、recover

panic

结构体

panic 关键字在 Go 语言的源代码是由数据结构runtime._panic表示的。每当我们调用 panic 都会创建一个如下所示的数据结构存储相关信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
type _panic struct {
	argp      unsafe.Pointer
	arg       interface{}
	link      *_panic
	recovered bool
	aborted   bool

	pc     uintptr
	sp     unsafe.Pointer
	goexit bool
}

结构体中字段含义说明:

……

阅读全文

mq|Kafka速度分析

Kafka的消息是保存或缓存在磁盘上的,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间,但是实际上,Kafka的特性之一就是高吞吐率。

即使是普通的服务器,Kafka也可以轻松支持每秒百万级的写入请求,超过了大部分的消息中间件,这种特性也使得Kafka在日志处理等海量数据场景广泛应用。

……

阅读全文

mq|kafka基础知识

kafka最初由Linkedin公司开发,是一个分布式、支持分区的、多副本的,基于zookeeper协调的分布式消息系统,用scala语言编写,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

……

阅读全文

Golang|垃圾回收

垃圾回收

垃圾回收(Garbage Collection,简称GC)是编程语言中提供的内存管理功能。

通过引入了语言层面的自动内存管理,也就是语言的使用者只用关注内存的申请而不必关心内存的释放,内存释放由虚拟机(virtual machine)或运行时(runtime)来自动进行管理。这种对不再使用的内存资源进行自动回收的功能就被称为垃圾回收。

……

阅读全文

redis|持久化存储

持久化流程

  • 客户端向服务端发送写操作(数据在客户端的内存中)。
  • 数据库服务端接收到写请求的数据(数据在服务端的内存中)。
  • 服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
  • 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
  • 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。

redis提供了RDB和AOF两种持久化存储方案

……

阅读全文

Golang|context

context意义

Go 中的 context 包在与 API 和慢处理交互时可以派上用场,特别是在生产级的 Web 服务中。在这些场景中,您可能想要通知所有的 goroutine 停止运行并返回。

context使用

context相关函数

1
2
3
4
5
6
7
8
//返回一个空 context, 这只能用于高等级(在 main 或顶级请求中),作为context的根节点
context.Background() Context
//返回一个空的 context,不知道用什么的时候就上这个
context.TODO() Context
context.WithValue(parent Context, key, val interface{}) (ctx Context, cancel CancelFunc)
context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)
context.WithDeadline(parent Context, d time.Time) (ctx Context, cancel CancelFunc)
context.WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancel CancelFunc)

context相关使用

Done方法取消

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func Stream(ctx context.Context, out chan<- Value) error {
	for {
		v, err := DoSomething(ctx)
		if err != nil {
			return err
		}
		select {
		case <-ctx.Done():
			return ctx.Err()
		case out <- v:
		}
	}
}

WithValue传值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	valueCtx := context.WithValue(ctx, key, "add value")
	go watch(valueCtx)
	time.Sleep(10 * time.Second)
	cancel()
	time.Sleep(5 * time.Second)
}

func watch(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			//get value
			fmt.Println(ctx.Value(key), "is cancel")
			return
		default:
			//get value
			fmt.Println(ctx.Value(key), "int goroutine")
			time.Sleep(2 * time.Second)
		}
	}
}

WithTimeout超时取消

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"fmt"
	"golang.org/x/net/context"
	"sync"
	"time"
)

var (
	wg sync.WaitGroup
)

func work(ctx context.Context) error {
	defer wg.Done()
	for i := 0; i < 1000; i++ {
		select {
		case <-time.After(2 * time.Second):
			fmt.Println("Doing some work ", i)
		// we received the signal of cancelation in this channel
		case <-ctx.Done():
			fmt.Println("Cancel the context ", i)
			return ctx.Err()
		}
	}
	return nil
}

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
	defer cancel()
	fmt.Println("Hey, I'm going to do some work")
	wg.Add(1)
	go work(ctx)
	wg.Wait()
	fmt.Println("Finished. I'm going home")
}

WithDeadline截止时间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	d := time.Now().Add(1 * time.Second)
	ctx, cancel := context.WithDeadline(context.Background(), d)
	defer cancel()
	select {
	case <-time.After(2 * time.Second):
		fmt.Println("oversleep")
	case <-ctx.Done():
		fmt.Println(ctx.Err())
	}
}

参考

  1. 理解 golang 中的 context(上下文)包
  2. Golang Context分析
  3. Go语言实战笔记(二十)Go Context
……

阅读全文

Golang|channel

channel结构体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type hchan struct {
	qcount   uint           //大小
	dataqsiz uint           //有缓存的队列大小
	buf      unsafe.Pointer //有缓存的循环队列指针
	elemsize uint16
	closed   uint32
	elemtype *_type //类型
	sendx    uint   //有缓存的可发送下标
	recvx    uint   //有缓存的可存储下标
	recvq    waitq  //接受的goroutine抽象出来的结构体sudog的队列,是一个双向链表
	sendq    waitq  //同上,是发送的相关链表
	lock     mutex  //互斥锁
}
type waitq struct {
	first *sudog
	last  *sudog
}

channel创建

1
ch := make(chan int, 3)

创建channel实际上就是在内存中实例化了一个hchan的结构体,并返回一个ch指针,我们使用过程中channel在函数之间的传递都是用的这个指针,这就是为什么函数传递中无需使用channel的指针,而直接用channel就行了,因为channel本身就是一个指针。

……

阅读全文