golang零内存分配的去抖动功能插件库debounce的使用

Golang零内存分配的去抖动功能插件库debounce的使用

简介

Debounce是一个简单、线程安全的去抖动库,用于Go语言。它会在最后一次调用后延迟指定时间才执行函数,非常适合用于限制频率、减少冗余操作以及在高频场景中优化性能。

特性

  • 零内存分配:在后续的去抖动调用中不会分配内存
  • 线程安全:可在多个goroutine中并发使用
  • 通道支持:可以在chan上使用Chan函数
  • 可配置延迟和限制:使用WithDelay和WithLimit选项设置自定义行为
  • 零依赖:仅使用Go标准库构建

安装

go get github.com/floatdrop/debounce/v2

使用示例

基本用法

import (
	"fmt"
	"time"

	"github.com/floatdrop/debounce/v2"
)

func main() {
	// 创建一个200毫秒延迟的去抖动器
	debouncer := debounce.New(debounce.WithDelay(200 * time.Millisecond))
	
	// 快速连续调用多次
	debouncer.Do(func() { fmt.Println("Hello") })
	debouncer.Do(func() { fmt.Println("World") })
	
	// 等待足够长时间让去抖动器执行
	time.Sleep(time.Second)
	// 输出: World
}

带通道的使用示例

import (
	"fmt"
	"time"

	"github.com/floatdrop/debounce/v2"
)

func main() {
	// 创建一个通道去抖动器,延迟500毫秒
	ch := make(chan struct{})
	debouncer := debounce.Chan(500 * time.Millisecond)
	
	go func() {
		for range debouncer(ch) {
			fmt.Println("事件触发")
		}
	}()
	
	// 快速发送多个事件
	ch <- struct{}{}
	ch <- struct{}{}
	ch <- struct{}{}
	
	// 等待足够长时间
	time.Sleep(time.Second)
	// 输出: 事件触发 (只输出一次)
}

带限制的使用示例

import (
	"fmt"
	"time"

	"github.com/floatdrop/debounce/v2"
)

func main() {
	// 创建一个去抖动器,延迟200毫秒,最多每100毫秒执行一次
	debouncer := debounce.New(
		debounce.WithDelay(200 * time.Millisecond),
		debounce.WithLimit(100 * time.Millisecond),
	)
	
	start := time.Now()
	
	// 快速连续调用多次
	for i := 0; i < 10; i++ {
		debouncer.Do(func() {
			fmt.Printf("执行于: %v\n", time.Since(start))
		})
		time.Sleep(50 * time.Millisecond)
	}
	
	time.Sleep(time.Second)
}

性能基准测试

go test -bench=. -benchmem

示例输出:

goos: darwin
goarch: arm64
pkg: github.com/floatdrop/debounce/v2
cpu: Apple M3 Max
BenchmarkDebounce_Insert-14    	 4860848	       234.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkDebounce_Do-14        	 5188065	       230.8 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/floatdrop/debounce/v2	7.805s

贡献

欢迎贡献代码!请随时提交Pull Request。

许可证

该项目采用MIT许可证。


更多关于golang零内存分配的去抖动功能插件库debounce的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang零内存分配的去抖动功能插件库debounce的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 零内存分配的去抖动(Debounce)功能实现

去抖动(Debounce)是一种常见的技术,用于限制函数调用的频率,确保在快速连续触发时只执行一次。下面我将介绍如何在Go中实现零内存分配的去抖动功能。

基本概念

去抖动的主要应用场景包括:

  • 按钮防重复点击
  • 搜索框输入联想
  • 窗口大小调整事件
  • 滚动事件处理

零内存分配实现

以下是零内存分配的debounce实现示例:

package debounce

import (
	"sync"
	"time"
)

type Debouncer struct {
	mu    sync.Mutex
	after time.Duration
	timer *time.Timer
}

func New(after time.Duration) *Debouncer {
	return &Debouncer{after: after}
}

func (d *Debouncer) Do(f func()) {
	d.mu.Lock()
	defer d.mu.Unlock()

	if d.timer != nil {
		d.timer.Stop()
	}

	d.timer = time.AfterFunc(d.after, f)
}

使用示例

package main

import (
	"debounce"
	"fmt"
	"time"
)

func main() {
	d := debounce.New(500 * time.Millisecond)
	
	for i := 0; i < 10; i++ {
		d.Do(func() {
			fmt.Println("Executed after debounce")
		})
		time.Sleep(100 * time.Millisecond)
	}
	
	time.Sleep(1 * time.Second)
}

高级特性实现

如果需要更复杂的功能,比如立即执行、取消等,可以扩展实现:

type DebounceOptions struct {
	Leading  bool // 是否立即执行第一次调用
	Trailing bool // 是否在延迟后执行最后一次调用
}

type AdvancedDebouncer struct {
	mu       sync.Mutex
	after    time.Duration
	timer    *time.Timer
	pending  bool
	options  DebounceOptions
	lastFunc func()
}

func NewAdvanced(after time.Duration, options DebounceOptions) *AdvancedDebouncer {
	return &AdvancedDebouncer{
		after:   after,
		options: options,
	}
}

func (d *AdvancedDebouncer) Do(f func()) {
	d.mu.Lock()
	defer d.mu.Unlock()

	d.lastFunc = f

	if d.timer != nil {
		d.timer.Stop()
	}

	if d.options.Leading && !d.pending {
		go d.lastFunc()
	}

	d.pending = true
	d.timer = time.AfterFunc(d.after, func() {
		d.mu.Lock()
		defer d.mu.Unlock()
		
		if d.options.Trailing && d.lastFunc != nil {
			go d.lastFunc()
		}
		
		d.pending = false
		d.lastFunc = nil
	})
}

func (d *AdvancedDebouncer) Cancel() {
	d.mu.Lock()
	defer d.mu.Unlock()
	
	if d.timer != nil {
		d.timer.Stop()
	}
	d.pending = false
	d.lastFunc = nil
}

性能优化

为了实现零内存分配,我们需要注意以下几点:

  1. 重用timer对象而不是每次创建新的
  2. 使用sync.Pool管理临时对象
  3. 避免闭包捕获外部变量导致内存分配

实际应用场景

// 搜索框输入联想
searchDebouncer := debounce.New(300 * time.Millisecond)

searchInput.OnChange(func(text string) {
    searchDebouncer.Do(func() {
        // 实际执行搜索
        performSearch(text)
    })
})

// 窗口大小调整
resizeDebouncer := debounce.New(100 * time.Millisecond)

window.OnResize(func() {
    resizeDebouncer.Do(func() {
        // 重新布局
        relayout()
    })
})

注意事项

  1. 确保在适当的时候调用Cancel(),比如组件卸载时
  2. 注意并发安全问题,多个goroutine调用Do()时需要同步
  3. 合理设置debounce时间间隔,太短达不到效果,太长影响用户体验

这种实现方式避免了频繁的内存分配,适合高性能要求的场景。

回到顶部