第三期学习总结

本文深入探讨Golang中的JSON解码不确定性、火焰图性能分析、REST与SOAP对比、优雅退出goroutine策略、三色标记垃圾回收算法及nil与empty集合区别,旨在提升开发者对Golang核心特性的理解和应用。
摘要由CSDN通过智能技术生成

跌跌撞撞一年时间,终于开始写第三期了 ,其实这一期的内容早就有了,只不过一直没有放到博客上。不能停下学习的脚步,要继续前进呀!

1、JSON unmarshal map的结果是不确定的

测试代码:

package main

import (
        "encoding/json"
        "log"
)

const str = `{"a":"aaaa","b":"baaa","c":100}`

func main() {
        for i := 0; i < 10; i++ {
                var m map[string]interface{}
                if err := json.Unmarshal([]byte(str), &m); err != nil {
                        log.Fatal(err)
                }
                for k, v := range m {
                        log.Printf("k: %s, v: %v", k, v)
                }
                log.Println("--------------------------------------")
        }
}

测试结果:

2、火焰图

火焰图(flame graph)是性能分析的利器,样子如下图所示

火焰图是基于perf结果产生的SVG图片,用来展示CPU的调用栈

y轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方就是它的父函数。

x轴表示抽样数,如果一个函数在x轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。

注意:x轴不代表时间,不是所有的调用栈合并后,按字母顺序排列的。

 

火焰图就是看顶层的哪个函数占据的宽度最大。只要有“平顶”,就表示该函数可能存在性能问题。颜色没有特殊含义,因为火焰图表示的是CPU的繁忙程度,所以一般选择暖色调。

参考:阮一峰-如何读懂火焰图:http://www.ruanyifeng.com/blog/2017/09/flame-graph.html

3、REST和SOAP

web服务技术有SOAP(Simple Object Access Protocol,简单对象访问协议)和REST(Representational State Transfer,表示性状态转移)两种方案。

 

SOAP是基于XML的简易协议,可使应用程序在HTTP之上进行信息交换。SOAP是用于访问网络服务的协议。

4、golang程序如何“优雅的退出”

goroutine作为golang并发的核心,不仅需要关注它们的创建和管理,也需要关注如何合理地退出这些协程。不合理退出可能会造成阻塞、panic、程序行为异常、数据结果不正确等问题。goroutine在退出方面,不像线程和进程,不能通过某种手段强制关闭它们,只能等待goroutine主动退出。下面介绍3种优雅退出goroutine的方法

 

(1)使用 for-range退出

for-range是使用频率很高的结构,常用来遍历数据,range能够感知channel的关闭,当channel被发送数据的协程关闭时,range就会结束,接着退出for循环。它在并发中的使用场景是:当协程只从1个channel读取数据,然后进行处理,处理后协程退出。下面举个例子,当in通道被关闭时,协程可自动退出。

go func(in <-chan int){
    //Using for-range to exit goroutine
    //range has the ability to detect the close/end of a channel
    for x := range in {
        fmt.Printf("Process %d\n", x)
    }
}(inCh)

(2)使用ok退出

for提供了多路复用的能力,所以for-select可以让函数具有持续多路处理多个channel的能力。但select没有感知channel的关闭,会引出2个问题:

1、继续在关闭的通道上读,会读到通道传输数据类型的零值,如果是指针类型,读到nil,继续处理还会产生nil

2、继续在关闭的通道上写,将会panic

 

处理方案:

第一种,如果某个通道关闭后,需要退出协程,直接return即可

go func() {
    for{
        select{
            case x, ok := <-in:
                if !ok{
                    return
                }
                fmt.Printf("Process %d\n", x)
                processedCnt++
            case <-t.C:
                fmt.Printf("Working, processedCnt = %d\n", processedCnt)
        }
    }
}()

第二种,如果某个通道关闭了,不再处理该通道,而是继续处理其他case,退出是等待所有的可读通道关闭。我们需要使用select的一个特征,select不会在nil的通道上进行等待。这种情况,把只读通道设置为nil即可解决

go func() {
    for{
        select{
            case x, ok := <-in1:
                if !ok{
                    in1=nil
                }
            case y, ok := <-in2:
                if !ok{
                    in2=nil
                }
            case <-t.C:
                fmt.Printf("Working, processedCnt = %d\n", processedCnt)
        }

        if in1 == nil && in2 == nil{
            return
        }
    }
}()

(3)使用退出通道退出

func worker(stopCh <- chan struct{}){
    go func() {
        defer fmt.Println("worker exit")
        for{
            select{
                case <- stopCh:
                    fmt.Println("Recv stop signal")
                    return
                case <- t.C:
                    fmt.Println("Working .")
            }
        }
    }()
    return
}

5、golang的三色标记算法

Go语言能够支持实时的,高并发的消息系统,在高达百万级别的消息系统中能够将延迟降低到100ms以下,很大一部分需要归功于Go高效的垃圾回收系统。

原理:

1、起初所有对象都是白色

2、从根出发扫描所有可达对象,标记为灰色,放入待处理队列

3、从队列取出灰色对象,将其引用对象标记为灰色放入队列,自身标记为黑色

4、重复3,直到灰色对象队列为空。此时白色对象即为垃圾,进行回收。

6、nil slice与empty slice的区别?

nil map与empty map的区别?

var slice []int

slice[1] = 0

会报数组越界的错误,因为只是声明了slice,没有给实例化的对象。如果是cpp的vector,就可以直接使用了,golang不行。

此时的slice的值是nil,这种情况下可以用于需要返回slice的函数,当函数出现异常的时候,保证函数依然会有nil的返回值。empty slice是指slice不为nil,但是slice没有值,slice的底层的空间是空的。此时的定义如下:

slice := make([]int, 0) 

或者

slice := []int{}

当我们查询或者处理一个空的列表的时候,非常有用,它会告诉我们返回的是一个列表,但是列表内没有任何值。

参考文档:

深度解析Go语言中「切片」的三种特殊状态:https://juejin.im/post/5bea58df6fb9a049f153bca8

nil slice可以用append吗?

测试代码:

var a []int

b := 2

a = append(a, b)

fmt.Printf("%v", a)



打印

[2]

可以append

 

但是map不行

测试代码:

var a map[string]string

a["a"] = "b"

fmt.Printf("%v", a)

会报错

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值