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) {
|
||||
for _, f := range bf.funcs {
|
||||
funcs := bf.funcs[:]
|
||||
for _, f := range funcs {
|
||||
bf.set.Set(f.hash(value))
|
||||
}
|
||||
}
|
||||
@ -36,7 +37,9 @@ func (bf *BloomFilter) Contains(value string) bool {
|
||||
return false
|
||||
}
|
||||
ret := true
|
||||
for _, f := range bf.funcs {
|
||||
|
||||
funcs := bf.funcs[:]
|
||||
for _, f := range funcs {
|
||||
ret = ret && bf.set.Test(f.hash(value))
|
||||
}
|
||||
return ret
|
||||
|
@ -16,7 +16,9 @@ func (r BytesResult) Hex() string {
|
||||
func (r BytesResult) UppercaseHex() string {
|
||||
dst := make([]byte, hex.EncodedLen(len(r)))
|
||||
j := 0
|
||||
for _, v := range r {
|
||||
|
||||
re := r[:]
|
||||
for _, v := range re {
|
||||
dst[j] = hextable[v>>4]
|
||||
dst[j+1] = hextable[v&0x0f]
|
||||
j += 2
|
||||
|
@ -42,7 +42,8 @@ func (z *zipPackage) Write(out *os.File) error {
|
||||
zipWriter := zip.NewWriter(out)
|
||||
defer zipWriter.Close()
|
||||
|
||||
for _, f := range z.files {
|
||||
files := z.files
|
||||
for _, f := range files {
|
||||
fileWriter, err := zipWriter.Create(f.name)
|
||||
if err != nil {
|
||||
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) {
|
||||
for _, k := range m.keys {
|
||||
keys := m.keys[:]
|
||||
for _, k := range keys {
|
||||
if v, ok := m.Get(k); ok {
|
||||
if f(k, v) {
|
||||
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 {
|
||||
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]))
|
||||
}
|
||||
|
||||
@ -53,7 +55,9 @@ func (s *mapSorter[T]) Keys() []string {
|
||||
|
||||
func (s *mapSorter[T]) Values() []T {
|
||||
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])
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,8 @@ func (s *Struct) Kind() reflect.Kind {
|
||||
|
||||
func (s *Struct) Names() []string {
|
||||
names := make([]string, len(s.fields))
|
||||
for i, f := range s.fields {
|
||||
fields := s.fields[:]
|
||||
for i, f := range fields {
|
||||
names[i] = f.name
|
||||
}
|
||||
|
||||
@ -45,7 +46,9 @@ func (s *Struct) Names() []string {
|
||||
|
||||
func (s *Struct) Values() []any {
|
||||
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)
|
||||
values = append(values, v.Interface())
|
||||
}
|
||||
@ -54,7 +57,8 @@ func (s *Struct) Values() []any {
|
||||
}
|
||||
|
||||
func (s *Struct) IsZero() bool {
|
||||
for _, fi := range s.fields {
|
||||
fields := s.fields[:]
|
||||
for _, fi := range fields {
|
||||
source := s.value.FieldByName(fi.name)
|
||||
if !source.IsZero() {
|
||||
return false
|
||||
@ -66,7 +70,9 @@ func (s *Struct) IsZero() bool {
|
||||
|
||||
func (s *Struct) ToMap() map[string]any {
|
||||
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)
|
||||
if fi.shouldIgnore(source) {
|
||||
continue
|
||||
@ -109,7 +115,8 @@ func (s *Struct) Copy(dest any) error {
|
||||
}
|
||||
|
||||
func (s *Struct) getByName(name string) (field, bool) {
|
||||
for i := range s.fields {
|
||||
fields := s.fields[:]
|
||||
for i := range fields {
|
||||
f := s.fields[i]
|
||||
if f.name == name {
|
||||
return f, true
|
||||
|
Reference in New Issue
Block a user