Go-并发安全字典

  • sync.Map
    • 一个 read 字典, 一个 dirty 字典
    • read 的键值对不一定全, dirty 的总是完全的(不包括被删除的键值对)
    • 适合读多写少的场景
    • 性能影响从大到小: 新增, 删除, 修改
  • 自己定义结构体, 明确键值类型
  • 通过反射实现一个统一的类型

上代码, 自己品:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var i int
	var list []string

	fmt.Println("int comparable: ", reflect.TypeOf(i).Comparable())      // true
	fmt.Println("slice comparable: ", reflect.TypeOf(list).Comparable()) // false

}
package main

import (
	"sync"
)

type IntStrMap struct {
	// m 不对外暴露, 所以只能使用 IntStrMap, 其成员方法都有明确的类型, 可以规律类型的问题
	m sync.Map
}

func (self *IntStrMap) Delete(key int) {
	self.m.Delete(key)
}

func (self *IntStrMap) Load(key int) (value string, ok bool) {
	v, ok := self.m.Load(key)
	if v != nil {
		value = v.(string)
	}
	return
}

func (self *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {
	a, loaded := self.m.LoadOrStore(key, value)
	actual = a.(string)
	return
}

func (self *IntStrMap) Store(key int, value string) {
	self.m.Store(key, value)
}

func (self *IntStrMap) Range(f func(key int, value string) bool) {
	self.m.Range(func(key, value interface{}) bool {
		return f(key.(int), value.(string))
	})
}
package main

import (
	"fmt"
	"reflect"
	"sync"
)

type ConcurrentMap struct {
	m         sync.Map
	keyType   reflect.Type
	valueType reflect.Type
}

func (self *ConcurrentMap) checkKeyType(key interface{}) (keyType reflect.Type, ok bool) {
	if self.keyType == nil {
		ok = true
		return
	}
	keyType = reflect.TypeOf(key)
	ok = keyType == self.keyType
	return
}

func (self *ConcurrentMap) checkValueType(value interface{}) (valueType reflect.Type, ok bool) {
	if self.valueType == nil {
		ok = true
		return
	}
	valueType = reflect.TypeOf(value)
	ok = valueType == self.valueType
	return
}

func (self *ConcurrentMap) checkStore(key interface{}, value interface{}) {
	// 不一定非要引发 panic, 也可以增加返回值来告知调用方, 或者在结构体定义一个字段
	if self.keyType == nil {
		keyType := reflect.TypeOf(key)
		if !keyType.Comparable() {
			panic(fmt.Errorf("错误的 key 类型: %v", keyType))
		}
		self.keyType = keyType
	} else if keyType, ok := self.checkKeyType(key); !ok {
		panic(fmt.Errorf("错误的 key 类型: %v", keyType))
	}

	if self.valueType == nil {
		self.valueType = reflect.TypeOf(value)
	} else if valueType, ok := self.checkValueType(value); !ok {
		panic(fmt.Errorf("错误的 value 类型: %v", valueType))
	}
}

func (self *ConcurrentMap) Delete(key interface{}) {
	if keyType, ok := self.checkKeyType(key); !ok {
		panic(fmt.Errorf("错误的 key 类型: %v", keyType))
	}
	self.m.Delete(key)
}

func (self *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) {
	if _, ok = self.checkKeyType(key); !ok {
		return
	}
	return self.m.Load(key)
}

func (self *ConcurrentMap) LoadOrStore(key interface{}, value interface{}) (actual interface{}, loaded bool) {
	self.checkStore(key, value)
	return self.m.LoadOrStore(key, value)
}

func (self *ConcurrentMap) Store(key interface{}, value interface{}) {
	self.checkStore(key, value)
	self.m.Store(key, value)
}

func (self *ConcurrentMap) Range(f func(key interface{}, value interface{}) bool) {
	self.m.Range(f)
}

func main() {
	cmap := ConcurrentMap{}

	cmap.Delete(3)

	cmap.Load("abc")

	fmt.Println(cmap.keyType, cmap.valueType) // <nil> <nil>

	actual, loaded := cmap.LoadOrStore(3, "abc-efg")
	fmt.Println("actual: ", actual) // abc-efg
	fmt.Println("loaded: ", loaded) // false

	fmt.Println(cmap.keyType, cmap.valueType) // int string

	cmap.Store(3, "abc")

	value, ok := cmap.Load(3)
	fmt.Println("value: ", value) // abc
	fmt.Println("ok: ", ok)       // true

	actual, loaded = cmap.LoadOrStore(3, "efg")
	fmt.Println("actual: ", actual) // abc
	fmt.Println("loaded: ", loaded) // true

	value, ok = cmap.Load("abc")
	fmt.Println("value: ", value) // <nil>
	fmt.Println("ok: ", ok)       // false

	cmap.Delete("abc") // panic: 错误的 key 类型: string

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我来为您演示一下如何使用 go-streams 进行并发控制。 首先,您需要安装 go-streams,可以通过以下命令进行安装: ``` go get github.com/reugn/go-streams ``` 接下来,我们可以使用 go-streams 提供的 `ConcurrentStreamBuilder` 和 `ConcurrentSinkBuilder` 来实现并发控制。 假设我们有一个需要处理的数据流,可以使用 `go-streams` 中的 `NewStreamBuilder` 来创建一个数据流: ```go streamBuilder := go_streams.NewStreamBuilder() ``` 然后,我们可以使用 `ConcurrentStreamBuilder` 来将数据流转换为并发处理的数据流,例如: ```go concurrentStreamBuilder := go_streams.NewConcurrentStreamBuilder(streamBuilder, 10) ``` 这里我们设置并发度为 10,表示最多会有 10 个 goroutine 同时处理数据。 接下来,我们需要为并发处理添加一个 Sink,可以使用 `ConcurrentSinkBuilder` 来创建: ```go concurrentSinkBuilder := go_streams.NewConcurrentSinkBuilder(concurrentStreamBuilder, 10) ``` 这里我们同样设置并发度为 10。 最后,我们可以将数据源和 Sink 连接起来,开始处理数据: ```go source := go_streams.NewSliceSource(data) sink := concurrentSinkBuilder.Build() source.Process(sink) ``` 这里的 `data` 可以是任何实现了 `Iterator` 接口的数据类型,例如 Go 中的数组、切片、映射或通道等。 以上就是使用 go-streams 进行并发控制的基本示例。如果您有其他问题或需要更详细的说明,请随时提问,我将尽力为您解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值