mirror of
https://github.com/charlienet/go-mixed.git
synced 2025-07-17 16:12:42 +08:00
优化range引用
This commit is contained in:
@ -26,7 +26,8 @@ func NewBloomFilter() *BloomFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (bf *BloomFilter) Add(value string) {
|
func (bf *BloomFilter) Add(value string) {
|
||||||
for _, f := range bf.funcs {
|
funcs := bf.funcs[:]
|
||||||
|
for _, f := range funcs {
|
||||||
bf.set.Set(f.hash(value))
|
bf.set.Set(f.hash(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,7 +37,9 @@ func (bf *BloomFilter) Contains(value string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ret := true
|
ret := true
|
||||||
for _, f := range bf.funcs {
|
|
||||||
|
funcs := bf.funcs[:]
|
||||||
|
for _, f := range funcs {
|
||||||
ret = ret && bf.set.Test(f.hash(value))
|
ret = ret && bf.set.Test(f.hash(value))
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
@ -16,7 +16,9 @@ func (r BytesResult) Hex() string {
|
|||||||
func (r BytesResult) UppercaseHex() string {
|
func (r BytesResult) UppercaseHex() string {
|
||||||
dst := make([]byte, hex.EncodedLen(len(r)))
|
dst := make([]byte, hex.EncodedLen(len(r)))
|
||||||
j := 0
|
j := 0
|
||||||
for _, v := range r {
|
|
||||||
|
re := r[:]
|
||||||
|
for _, v := range re {
|
||||||
dst[j] = hextable[v>>4]
|
dst[j] = hextable[v>>4]
|
||||||
dst[j+1] = hextable[v&0x0f]
|
dst[j+1] = hextable[v&0x0f]
|
||||||
j += 2
|
j += 2
|
||||||
|
@ -42,7 +42,8 @@ func (z *zipPackage) Write(out *os.File) error {
|
|||||||
zipWriter := zip.NewWriter(out)
|
zipWriter := zip.NewWriter(out)
|
||||||
defer zipWriter.Close()
|
defer zipWriter.Close()
|
||||||
|
|
||||||
for _, f := range z.files {
|
files := z.files
|
||||||
|
for _, f := range files {
|
||||||
fileWriter, err := zipWriter.Create(f.name)
|
fileWriter, err := zipWriter.Create(f.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -88,7 +88,8 @@ func (m *sorted_map[K, V]) Iter() <-chan *Entry[K, V] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *sorted_map[K, V]) ForEach(f func(K, V) bool) {
|
func (m *sorted_map[K, V]) ForEach(f func(K, V) bool) {
|
||||||
for _, k := range m.keys {
|
keys := m.keys[:]
|
||||||
|
for _, k := range keys {
|
||||||
if v, ok := m.Get(k); ok {
|
if v, ok := m.Get(k); ok {
|
||||||
if f(k, v) {
|
if f(k, v) {
|
||||||
break
|
break
|
||||||
|
81
panic/panic.go
Normal file
81
panic/panic.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package panic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Panic struct {
|
||||||
|
R any
|
||||||
|
Stack []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Panic) String() string {
|
||||||
|
return fmt.Sprintf("%v\n%s", p.R, p.Stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PanicGroup struct {
|
||||||
|
panics chan Panic // 致命错误通知
|
||||||
|
dones chan int // 协程完成通知
|
||||||
|
jobs chan int // 并发数量
|
||||||
|
jobN int32 // 工作协程数量
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPanicGroup(maxConcurrent int) *PanicGroup {
|
||||||
|
return &PanicGroup{
|
||||||
|
panics: make(chan Panic, 8),
|
||||||
|
dones: make(chan int, 8),
|
||||||
|
jobs: make(chan int, maxConcurrent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PanicGroup) Go(f func()) *PanicGroup {
|
||||||
|
g.jobN++
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
g.jobs <- 1
|
||||||
|
defer func() {
|
||||||
|
<-g.jobs
|
||||||
|
// go 语言只能在自己的协程中捕获自己的 panic
|
||||||
|
// 如果不处理,整个*进程*都会退出
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
g.panics <- Panic{R: r, Stack: debug.Stack()}
|
||||||
|
// 如果发生 panic 就不再通知 Wait() 已完成
|
||||||
|
// 不然就可能出现 g.jobN 为 0 但 g.panics 非空
|
||||||
|
// 的情况,此时 Wait() 方法需要在正常结束的分支
|
||||||
|
// 中再额外检查是否发生了 panic,非常麻烦
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.dones <- 1
|
||||||
|
}()
|
||||||
|
|
||||||
|
f()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PanicGroup) Wait(ctx context.Context) error {
|
||||||
|
if g.jobN == 0 {
|
||||||
|
panic("no job to wait")
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-g.dones: // 协程正常结束
|
||||||
|
g.jobN--
|
||||||
|
if g.jobN == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case p := <-g.panics: // 协程有 panic
|
||||||
|
panic(p)
|
||||||
|
case <-ctx.Done():
|
||||||
|
// 整个 ctx 结束,超时或者调用方主动取消
|
||||||
|
// 子协程应该共用该 ctx,都会收到相同的结束信号
|
||||||
|
// 不需要在这里再去通知各协程结束(实现起来也麻烦)
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
panic/panic_test.go
Normal file
32
panic/panic_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package panic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPanic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
t.Log("捕捉异常")
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if err, ok := e.(error); ok {
|
||||||
|
t.Log(err.Error())
|
||||||
|
}
|
||||||
|
t.Log("格式化:", e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
g := NewPanicGroup(10)
|
||||||
|
g.Go(func() {
|
||||||
|
panic("1243")
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := g.Wait(context.Background()); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
fmt.Println("这条消息可打印")
|
||||||
|
}
|
@ -40,7 +40,9 @@ func (s *mapSorter[T]) Desc() *mapSorter[T] {
|
|||||||
|
|
||||||
func (s *mapSorter[T]) Join(sep string, f func(k string, v T) string) string {
|
func (s *mapSorter[T]) Join(sep string, f func(k string, v T) string) string {
|
||||||
slice := make([]string, 0, len(s.m))
|
slice := make([]string, 0, len(s.m))
|
||||||
for _, k := range s.keys {
|
|
||||||
|
keys := s.keys[:]
|
||||||
|
for _, k := range keys {
|
||||||
slice = append(slice, f(k, s.m[k]))
|
slice = append(slice, f(k, s.m[k]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +55,9 @@ func (s *mapSorter[T]) Keys() []string {
|
|||||||
|
|
||||||
func (s *mapSorter[T]) Values() []T {
|
func (s *mapSorter[T]) Values() []T {
|
||||||
ret := make([]T, 0, len(s.m))
|
ret := make([]T, 0, len(s.m))
|
||||||
for _, k := range s.keys {
|
|
||||||
|
keys := s.keys[:]
|
||||||
|
for _, k := range keys {
|
||||||
ret = append(ret, s.m[k])
|
ret = append(ret, s.m[k])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ func (s *Struct) Kind() reflect.Kind {
|
|||||||
|
|
||||||
func (s *Struct) Names() []string {
|
func (s *Struct) Names() []string {
|
||||||
names := make([]string, len(s.fields))
|
names := make([]string, len(s.fields))
|
||||||
for i, f := range s.fields {
|
fields := s.fields[:]
|
||||||
|
for i, f := range fields {
|
||||||
names[i] = f.name
|
names[i] = f.name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,9 @@ func (s *Struct) Names() []string {
|
|||||||
|
|
||||||
func (s *Struct) Values() []any {
|
func (s *Struct) Values() []any {
|
||||||
values := make([]any, 0, len(s.fields))
|
values := make([]any, 0, len(s.fields))
|
||||||
for _, fi := range s.fields {
|
|
||||||
|
fields := s.fields[:]
|
||||||
|
for _, fi := range fields {
|
||||||
v := s.value.FieldByName(fi.name)
|
v := s.value.FieldByName(fi.name)
|
||||||
values = append(values, v.Interface())
|
values = append(values, v.Interface())
|
||||||
}
|
}
|
||||||
@ -54,7 +57,8 @@ func (s *Struct) Values() []any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Struct) IsZero() bool {
|
func (s *Struct) IsZero() bool {
|
||||||
for _, fi := range s.fields {
|
fields := s.fields[:]
|
||||||
|
for _, fi := range fields {
|
||||||
source := s.value.FieldByName(fi.name)
|
source := s.value.FieldByName(fi.name)
|
||||||
if !source.IsZero() {
|
if !source.IsZero() {
|
||||||
return false
|
return false
|
||||||
@ -66,7 +70,9 @@ func (s *Struct) IsZero() bool {
|
|||||||
|
|
||||||
func (s *Struct) ToMap() map[string]any {
|
func (s *Struct) ToMap() map[string]any {
|
||||||
m := make(map[string]any, len(s.fields))
|
m := make(map[string]any, len(s.fields))
|
||||||
for _, fi := range s.fields {
|
|
||||||
|
fields := s.fields[:]
|
||||||
|
for _, fi := range fields {
|
||||||
source := s.value.FieldByName(fi.name)
|
source := s.value.FieldByName(fi.name)
|
||||||
if fi.shouldIgnore(source) {
|
if fi.shouldIgnore(source) {
|
||||||
continue
|
continue
|
||||||
@ -109,7 +115,8 @@ func (s *Struct) Copy(dest any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Struct) getByName(name string) (field, bool) {
|
func (s *Struct) getByName(name string) (field, bool) {
|
||||||
for i := range s.fields {
|
fields := s.fields[:]
|
||||||
|
for i := range fields {
|
||||||
f := s.fields[i]
|
f := s.fields[i]
|
||||||
if f.name == name {
|
if f.name == name {
|
||||||
return f, true
|
return f, true
|
||||||
|
Reference in New Issue
Block a user