0%

Ants

high-performance and low-cost goroutine pool
使用Golang编写的低成本高性能的goroutine池

池子类型

  • Pool
  • PoolWithFunc
  • MultiPool
  • MultiPoolWithFunc

源码偶得自旋锁🔗

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
// Copyright 2019 Andy Pan & Dietoad. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package sync

import (
"runtime"
"sync"
"sync/atomic"
)

type spinLock uint32

const maxBackoff = 16

func (sl *spinLock) Lock() {
backoff := 1
for !atomic.CompareAndSwapUint32((*uint32)(sl), 0, 1) {
// Leverage the exponential backoff algorithm, see https://en.wikipedia.org/wiki/Exponential_backoff.
for i := 0; i < backoff; i++ {
runtime.Gosched()
}
if backoff < maxBackoff {
backoff <<= 1
}
}
}

func (sl *spinLock) Unlock() {
atomic.StoreUint32((*uint32)(sl), 0)
}

// NewSpinLock instantiates a spin-lock.
func NewSpinLock() sync.Locker {
return new(spinLock)
}

两个关键点

  • 指数避让
1
2
3
if backoff < maxBackoff {
backoff <<= 1 // 当小于最大避让次数,左移一位(即为2^(n+1))
}
  • runtime.Gosched

    runtime.Gosched() 是一个用于让出当前 goroutine 的调度器,以便让其他 goroutine 运行的函数。它不会明确指定让出 CPU 的时间,而是将当前 goroutine 放回到调度队列中,允许 Go 调度器选择运行其他可运行的 goroutine。实际上,它让出的是调度机会,而不是具体的时间片。

    • 让出调度:当前 goroutine 将自己放回到调度队列中,并且可能会立即被重新调度运行,或者在其他 goroutine 运行之后再被调度运行。
    • 不阻塞:runtime.Gosched() 不会阻塞当前 goroutine,而是让出调度之后继续执行。

扩展

time.Sleep 与 runtime.Gosched 的对比

  • time.Sleep:
    • 让出 CPU 时间片并进入睡眠状态,直到指定的时间结束。
    • 睡眠时间可以非常短(如 time.Nanosecond),也可以比较长。
    • 在睡眠期间,该 goroutine 不会被调度运行。
  • runtime.Gosched:
    • 立即让出当前 goroutine 的调度权,但没有指定具体的时间。
    • 当前 goroutine 会被放回调度队列,调度器可以立即或者稍后重新调度该 goroutine。

1. 问题

观看以下代码

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
package main

import (
"fmt"
"unsafe"
)

type S1 struct {
a struct{}
b int8
c int64
}

type S2 struct {
a int8
b int64
c struct{}
}

func main() {
var (
s1 S1
s2 S2
)
fmt.Printf("unsafe.Sizeof(s1): %v\n", unsafe.Sizeof(s1))
fmt.Printf("unsafe.Sizeof(s2): %v\n", unsafe.Sizeof(s2))
}
1.1 分析
  • S1

    1. a字段为struct{},不占内存,0字节
    2. b字段为int8,对齐长度1, 占1字节
    3. c字段为int64,对齐长度8,前两个字段只占用了1字节,所以填充7字节,对齐到八字节位

    所以S1占用16字节

  • S2

    1. a字段为int8,对齐长度1, 占1字节
    2. b字段为int64,对齐长度8,a字段只占用了1字节,所以填充7字节,对齐到八字节位
    3. a字段为struct{},不占内存,0字节

    所以S2占用16字节

真的对吗?,看看输出

1
2
unsafe.Sizeof(s1): 16
unsafe.Sizeof(s2): 24

为什么呢?我们看看golang仓库中的这个issue 9401,建议自己看比较好。

机翻一下
issue9401
那么当0字符字段在结构体最后时,多出的一个结构体对齐长度,是为了防止结构体指针之乡结构体外部,即无效指针。

1. 安装方案

  • wine-for-wechat配合wine-wechat-setup无脑爽,这是archlinuxcn源中的包

2. 准备

2.1 ArchlinuxCN源配置

根据archlinuxcn完成archlinuxcn源配置,然后使用sudo pacman -Syu更新源

2.2 下载Wechat安装包

下载最新的wechat 64位安装包

阅读全文 »

1. 应用场景

例如当我们更新了配置文件,但是我们不想停止程序重启

2. 实现思想

在我们检测到配置文件更改时,进行进程替换,但如果我们开启子进程,杀死父进程,会产生孤儿进程

阅读全文 »

本文以及评论记录了平时的一些问题

  • music-downloader
    • music-downloader的歌曲名还是会出现字符错误,继续排查
    • DONE: qq-music-api中没有check是否获取到歌词

1.前言

你需要确保你已经安装好了 Arch 或其他发行版的 Linux,并且已经接入互联网、配置好了你的 pacman.confmirrorlist

Tips: 如果您已接触过其他桌面管理器,可直接跳转至安装

2.安装 Xorg

Xorg (通常简称为 X )是 Linux 用户中最流行的显示服务器。 它无处不在,使其成为 GUI 应用程序永远存在的必要条件,从而导致大多数发行版的大量采用。wiki
xorg 是 dwm 乃至大多数桌面环境的基础(hyprrland 除外).

1
sudo pacman -S xorg xorg-server xorg-apps

xorg-apps 中包括了很多有用的工具,例如xrandrxpropxmodmapxsetroot

阅读全文 »

部分初学者使用web框架时会发现每个handler都会传入一个context,但并没有深究他的作用,甚至直接传入一个context.Background()草草了事。本文结合我在工作中的实际场景,盘点下context的使用

1. 控制goroutine

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
package main

import (
"sync"
)

var wg sync.WaitGroup

func main() {
wg.Add(1)
go func() {
defer wg.Done()
daemon1()
}()

wg.Add(1)
go func() {
defer wg.Done()
daemon2()
}()

wg.Wait()
}

func daemon1() {
// 开启8080端口tcp监听,并处理连接
}

func daemon2() {
// 开启8080端口udp监听,并处理连接
}

如上,我们在main函数中启动了两个守护协程,并使用WaitGroup等待goroutine结束,但由于daemon中监听并处理,一般有for {}结构,无法退出。当我们退出主协程,由于等待,会导致我们的程序卡死

阅读全文 »

1. DB 和 Cache 的数据一致性

  • 延迟双删

  • binlog 异步更新

XSS 攻击

Grpc 和 HTTP1.1 应用场景的差别

gRPC 是一种高性能的 RPC(Remote Procedure Call)框架,它使用 Protocol Buffers 进行序列化和反序列化,支持多种编程语言,并提供了丰富的特性,如流式处理、认证和授权等。在微服务场景下,由于 gRPC 使用二进制协议进行通信,因此它的效率和吞吐量都比 RESTful API 更高。此外,gRPC 还提供了更加丰富的服务定义和代码生成工具,可以更加方便地生成客户端和服务器端的代码。
而 RESTful API 则是一种基于 HTTP 协议的 API 设计风格,它使用 JSON、XML 等文本格式进行序列化和反序列化,具有简单、灵活、易于理解和使用的特点。RESTful API 适用于基于 HTTP 的应用程序,比如 Web 应用程序、移动应用程序等,且可以跨语言和平台使用。在微服务场景下,RESTful API 具有更加广泛的应用场景,比如服务暴露、API 网关等。
因此,选择 gRPC 还是 RESTful API 需要根据具体需求和场景进行选择。如果需要高性能、高吞吐量的微服务之间通信,或者需要流式处理、认证和授权等高级特性,可以选择 gRPC;如果需要简单、灵活、易于理解和使用的 API,或者需要跨语言和平台使用,可以选择 RESTful API。

waiting to learn

1. 字符串匹配算法(KMP)

2. LIS(最长递增子序列)

3. LCS(最长公共子序列)

4. LCP(最长公共前缀)

5. LPS(最长回文子序列)

6. ED(最小编辑距离)