golang 琐碎知识(持续进行)

时间格式

time.now.Format("2006-01-02T 15:04:05")

make声明切片bug

Golang:statusList := make([]*model.StatusList, 6)
会声明一个长为6的null切片,使用append添加时不会将null覆盖掉

去掉切片末尾元素

segments[:len(segments)-1]

互斥锁

var signal = make(chan struct{}, 1)
func Test() {
	signal <- struct{}{}
	defer func() {
		<-signal
	}()
}
var mu sync.Mutex
func Test() {
	mu.Lock()
	defer mu.Unlock()
}
var signal = make(chan struct{}, 1)

func IsPortAvailable(port int) bool {
	address := fmt.Sprintf("%s:%d", "0.0.0.0", port)
	listener, err := net.Listen("tcp", address)
	if err != nil {
		log.Printf("port %s is taken: %s", address, err)
		return false
	}

	defer listener.Close()
	return true
}

var avaiblePort = 1000

func GetAvailablePort() int {
	var j int
	signal <- struct{}{}
	for {
		avaiblePort++
		j = avaiblePort
		if IsPortAvailable(j) {
			break
		}
	}
	<-signal

	return j
}

panic recover

参考:https://geektutu.com/post/gee-day7.html

core dump 打印堆栈信息

https://blog.csdn.net/xmcy001122/article/details/105665732?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-105665732-blog-103850401.pc_relevant_3mothn_strategy_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3-105665732-blog-103850401.pc_relevant_3mothn_strategy_recovery&utm_relevant_index=3

任务队列,执行异步任务时需要考虑异步worker

https://lailin.xyz/post/go-training-03.html

编写实例:https://gitee.com/huoyingwhw/go_async_task

goroutineGorecovergoroutine
func Go(f func()){
    go func(){
        defer func(){
            if err := recover(); err != nil {
                log.Printf("panic: %+v", err)
            }
        }()

        f()
    }()
}

panic两种出现情况:

  • 没有预期的一种异常的发生,自动抛出
  • 预期的抛出

设计模式

https://lailin.xyz/post/singleton.html

任务队列machinery使用与源码剖析

https://cloud.tencent.com/developer/article/1169675

redis 消息队列 golang

https://juejin.cn/post/7058699128284381221

golang build编译

golang 消息队列

NSQ,介绍:https://cloud.tencent.com/developer/article/1896007

golang 使用sqlite

https://learnku.com/docs/build-web-application-with-golang/053-uses-the-sqlite-database/3183

golang 分布式数据流转

https://juejin.cn/post/7088262766779170853

go test 添加性能打印

go test -benchmem -bench=“.” -v singleton.go singleton_test.go

多态

什么是多态?

概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。

为什么要用多态呢?

原因:我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。耦合度讲的是模块模块之间,代码代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。

多态有什么好处?

有两个好处:

  • 1、应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。//继承
  • 2、派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。 //多态的真正作用,

golang crypto/rsa 使用教程

https://zhuanlan.zhihu.com/p/384595092

golang 同步包

go mod tidy

面向对象的编程思维详解

https://github.com/aceld/golang/blob/main/6%E3%80%81%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E7%90%86%E8%A7%A3interface.md#6%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BC%96%E7%A8%8B%E6%80%9D%E7%BB%B4%E7%90%86%E8%A7%A3interface

//实现架构层(基于抽象层进行业务封装-针对interface接口进行封装)
func BankerBusiness(banker AbstractBanker) {
	//通过接口来向下调用,(多态现象)
	banker.DoBusi()
}

解决exec.Start() 产生僵尸进程无法回收

// 执行shell
func ExecShell(s string) error {
	//execComand := func() error {
	//	err := exec.Command("/bin/bash", "-c", s).Start()
	//	logging.Infof("utils.ExecShell 脚本: %s\n", s)
	//	if err != nil {
	//		return err
	//	}
	//
	//}

	ctx := context.Background()

	cmd := exec.CommandContext(ctx, "/bin/bash", "-c", s)

	cmd.SysProcAttr = &syscall.SysProcAttr{}

	err := cmd.Start()
	if err != nil {
		return err
	}

	logging.Infof("utils.ExecShell 脚本: %s\n", s)

	// 监听进程wait,回收子进程
	errCmdCh := make(chan error, 1)

	go func() {
		go func() {
			errCmdCh <- cmd.Wait()
		}()
		for {
			select {
			case <-ctx.Done():
				logging.Infof("utils.ExecShell ctx.done\n")
				pid := cmd.Process.Pid
				if err := syscall.Kill(-1*pid, syscall.SIGKILL); err != nil {
					return
				}
                //想要杀死整个进程组,而不是单个进程,需要传递负数形式。
			case err := <-errCmdCh:
				if err != nil {
					logging.Errorf("utils.ExecShell 脚本: s, errCmdCh error %+v \n", s, err)
				}
				return
			default:
				time.Sleep(1 * time.Second)
			}
		}
	}()


	return nil
}

参考:https://blog.csdn.net/af2251337/article/details/125357359

注意指针问题

在实际开发中遇到了一个比较棘手的问题,在循环外声明了一个对象,然后循环内更改值并把地址赋值给另外一个对象,然后将该对象append一个切片中,因为是指针赋值,所以在该切片中存在的全是同一个地址,因此值也是一样的,都是最后一次赋值的内容。

golang 异步任务需传参

永不停息!!!:
大佬请教一下,我现在使用go关键字实现了异步任务,但是我这个地方有个疑问,就是taskResultService 这个对象要不要当作入参传入go关键字开启的这个匿名函数里面,像我这样使用有没有问题呀
代码:
func A(c *gin.Context) {
	var err error
	taskResultService := &service.TaskResultService{}
	err = c.ShouldBindJSON(&taskResultService.M)
	if err != nil {
		logging.Errorf("api.HandleTaskResult: bind json 失败, err: %v\n", err)
		c.JSON(400, utils.SyncErrorResponse(err))
		return
	}
	// sync response
	c.JSON(0, utils.SyncSuccessResponse())
	// async execute
	go func() {
		logging.Infof("api.HandleTaskResult: 开始获取任务结果目录 [%s]\n", taskResultService.M.BaseInfo.TaskId)
		// auth token
		ttSecret, err := oauthc.Agent2ServerAuthGetToken(taskResultService.M.BaseInfo.TaskId)
		if err != nil {
			logging.Errorf("api.HandleTaskResult: 从mysql获取token失败, err: %v\n", err)
			return
		}
	}()
}

ㅤ:
你这个可以不用

永不停息!!!:
这样使用的话,默认就把taskResultService这个对象传过去了吗,这里面的底层逻辑是怎样的,能详细说一下吗

ㅤ:
不是默认传进去了  你可以简单理解为for大括号里用了大括号外的变量 是一个原理

永不停息!!!:
如果存在并发的话,有多个taskResultService对象,会不会引起参数错乱

ㅤ:
会 如果你在for 循环里 开协程  用for语句里的变量。你会发现所有协程用的是for语句的最后一个值

那就只能传入参数来避免咯

golang 释放互斥锁

//var mutex sync.Mutex
//
//func MutexText() {
// defer func() {
//    if err := recover(); err != nil {
//       log.Println(err)
//    }
// }()
// log.Println("尝试获得锁")
// flag := mutex.TryLock()
// defer mutex.Unlock()
// log.Println(flag)
// log.Println("获得锁")
// time.Sleep(time.Second*3)
// panic("错误")
//
//}

func main() {
	//for i:=0; i<2; i++ {
	//	log.Println("123")
	//	go MutexText()
	//}
}

er(); err != nil {
// log.Println(err)
// }
// }()
// log.Println(“尝试获得锁”)
// flag := mutex.TryLock()
// defer mutex.Unlock()
// log.Println(flag)
// log.Println(“获得锁”)
// time.Sleep(time.Second*3)
// panic(“错误”)
//
//}

func main() {
//for i:=0; i<2; i++ {
// log.Println(“123”)
// go MutexText()
//}
}

结构体嵌套序列化

package main

import (
	"encoding/json"
	"log"
)

type Person struct {
	Name string `json:"name"`
	Author
}

type Author struct {
	Id string `json:"id"`
}

func main() {
	p := new(Person)
	p.Name = "zzy"
	p.Id = "123"
	body, err := json.Marshal(p)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("marshal : ", string(body))
}
// output:
2023/01/16 10:49:51 marshal :  {"name":"zzy","id":"123"}

闭包

golang的闭包是指函数内部声明了一个匿名函数,改函数是环境+匿名函数的组合,是引用了变量的函数,因此变量会常驻内存,不会立即销毁。