# Concurrency 并发包包含一些支持并发编程的功能。例如:goroutine, channel 等。
## 源码: - [https://github.com/duke-git/lancet/blob/main/concurrency/channel.go](https://github.com/duke-git/lancet/blob/main/concurrency/channel.go) - [https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go](https://github.com/duke-git/lancet/blob/main/concurrency/keyed_locker.go) ## 用法: ```go import ( "github.com/duke-git/lancet/v2/concurrency" ) ``` ## 目录 ### Channel - [NewChannel](#NewChannel) - [Bridge](#Bridge) - [FanIn](#FanIn) - [Generate](#Generate) - [Or](#Or) - [OrDone](#OrDone) - [Repeat](#Repeat) - [RepeatFn](#RepeatFn) - [Take](#Take) - [Tee](#Tee) ### KeyedLocker - [NewKeyedLocker](#NewKeyedLocker) - [KeyedLocker_Do](#Do) - [NewRWKeyedLocker](#NewRWKeyedLocker) - [RLock](#RLock) - [Lock](#Lock) - [NewTryKeyedLocker](#NewTryKeyedLocker) - [TryLock](#TryLock) - [Unlock](#Unlock) ## 文档 ### Channel ### NewChannel返回一个Channel指针实例
函数签名: ```go type Channel[T any] struct func NewChannel[T any]() *Channel[T] ``` 示例:[运行](https://go.dev/play/p/7aB4KyMMp9A) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { c := concurrency.NewChannel[int]() } ``` ### Bridge将多个channel链接到一个channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T ``` 示例:[运行](https://go.dev/play/p/qmWSy1NVF-Y) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() genVals := func() <-chan <-chan int { out := make(chan (<-chan int)) go func() { defer close(out) for i := 1; i <= 5; i++ { stream := make(chan int, 1) stream <- i close(stream) out <- stream } }() return out } for v := range c.Bridge(ctx, genVals()) { fmt.Println(v) } // Output: // 1 // 2 // 3 // 4 // 5 } ``` ### FanIn将多个channel合并为一个channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T ``` 示例:[运行](https://go.dev/play/p/2VYFMexEvTm) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() channels := make([]<-chan int, 2) for i := 0; i < 2; i++ { channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2) } chs := c.FanIn(ctx, channels...) for v := range chs { fmt.Println(v) //1 1 0 0 or 0 0 1 1 } } ``` ### Generate根据传入的值,生成channel.
函数签名: ```go func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T ``` 示例:[运行](https://go.dev/play/p/7aB4KyMMp9A) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() intStream := c.Generate(ctx, 1, 2, 3) fmt.Println(<-intStream) fmt.Println(<-intStream) fmt.Println(<-intStream) // Output: // 1 // 2 // 3 } ``` ### Repeat返回一个channel,将参数`values`重复放入channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T ``` 示例:[运行](https://go.dev/play/p/k5N_ALVmYjE) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4) for v := range intStream { fmt.Println(v) } // Output: // 1 // 2 // 1 // 2 } ``` ### RepeatFn返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T ``` 示例:[运行](https://go.dev/play/p/4J1zAWttP85) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() fn := func() string { return "hello" } c := concurrency.NewChannel[string]() intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3) for v := range intStream { fmt.Println(v) } // Output: // hello // hello // hello } ``` ### Or将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。
函数签名: ```go func (c *Channel[T]) Or(channels ...<-chan T) <-chan T ``` 示例:[运行](https://go.dev/play/p/Wqz9rwioPww) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { sig := func(after time.Duration) <-chan any { c := make(chan any) go func() { defer close(c) time.Sleep(after) }() return c } start := time.Now() c := concurrency.NewChannel[any]() <-c.Or( sig(1*time.Second), sig(2*time.Second), sig(3*time.Second), ) fmt.Println("done after %v", time.Since(start)) //1.003s } ``` ### OrDone将一个channel读入另一个channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T ``` 示例:[运行](https://go.dev/play/p/lm_GoS6aDjo) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() intStream := c.Take(ctx, c.Repeat(ctx, 1), 3) for v := range c.OrDone(ctx, intStream) { fmt.Println(v) } // Output: // 1 // 1 // 1 } ``` ### Take返回一个channel,其值从另一个channel获取,直到取消上下文。
函数签名: ```go func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T ``` 示例:[运行](https://go.dev/play/p/9Utt-1pDr2J) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() numbers := make(chan int, 5) numbers <- 1 numbers <- 2 numbers <- 3 numbers <- 4 numbers <- 5 defer close(numbers) c := concurrency.NewChannel[int]() intStream := c.Take(ctx, numbers, 3) for v := range intStream { fmt.Println(v) } // Output: // 1 // 2 // 3 } ``` ### Tee将一个channel分成两个channel,直到取消上下文。
函数签名: ```go func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) ``` 示例:[运行](https://go.dev/play/p/3TQPKnCirrP) ```go package main import ( "context" "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() c := concurrency.NewChannel[int]() intStream := c.Take(ctx, c.Repeat(ctx, 1), 2) ch1, ch2 := c.Tee(ctx, intStream) for v := range ch1 { fmt.Println(v) fmt.Println(<-ch2) } // Output: // 1 // 1 // 1 // 1 } ``` ### KeyedLocker ### NewKeyedLockerNewKeyedLocker创建一个新的KeyedLocker,并为锁的过期设置指定的 TTL。KeyedLocker 是一个简单的键值锁实现,允许非阻塞的锁获取。
函数签名: ```go func NewKeyedLocker[K comparable](ttl time.Duration) *KeyedLocker[K] ``` 示例:[运行](https://go.dev/play/p/GzeyC33T5rw) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewKeyedLocker[string](2 * time.Second) task := func() { fmt.Println("Executing task...") time.Sleep(1 * time.Second) fmt.Println("Task completed.") } ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if err := locker.Do(ctx, "mykey", task); err != nil { log.Fatalf("Error executing task: %v\n", err) } else { fmt.Println("Task successfully executed.") } ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second) defer cancel2() if err := locker.Do(ctx2, "mykey", task); err != nil { log.Fatalf("Error executing task: %v\n", err) } else { fmt.Println("Task successfully executed.") } // Output: // Executing task... // Task completed. // Task successfully executed. // Executing task... // Task completed. // Task successfully executed. } ``` ### Do为指定的键获取锁并执行提供的函数。
函数签名: ```go func (l *KeyedLocker[K]) Do(ctx context.Context, key K, fn func()) error ``` 示例:[运行](https://go.dev/play/p/GzeyC33T5rw) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewKeyedLocker[string](2 * time.Second) task := func() { fmt.Println("Executing task...") time.Sleep(1 * time.Second) fmt.Println("Task completed.") } ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() if err := locker.Do(ctx, "mykey", task); err != nil { log.Fatalf("Error executing task: %v\n", err) } else { fmt.Println("Task successfully executed.") } ctx2, cancel2 := context.WithTimeout(context.Background(), 3*time.Second) defer cancel2() if err := locker.Do(ctx2, "mykey", task); err != nil { log.Fatalf("Error executing task: %v\n", err) } else { fmt.Println("Task successfully executed.") } // Output: // Executing task... // Task completed. // Task successfully executed. // Executing task... // Task completed. // Task successfully executed. } ``` ### NewRWKeyedLockerNewRWKeyedLocker创建一个新的RWKeyedLocker,并为锁的过期设置指定的 TTL。RWKeyedLocker 是一个简单的键值读写锁实现,允许非阻塞的锁获取。
函数签名: ```go func NewRWKeyedLocker[K comparable](ttl time.Duration) *RWKeyedLocker[K] ``` 示例:[运行](https://go.dev/play/p/CkaJWWwZm9) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewRWKeyedLocker[string](2 * time.Second) // Simulate a key key := "resource_key" fn := func() { fmt.Println("Starting write operation...") // Simulate write operation, assuming it takes 2 seconds time.Sleep(200 * time.Millisecond) fmt.Println("Write operation completed!") } // Acquire the write lock and execute the operation ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() // Execute the lock operation with a 3-second timeout err := locker.Lock(ctx, key, fn) if err != nil { return } //output: //Starting write operation... //Write operation completed! } ``` ### RLockRLock为指定的键获取读锁并执行提供的函数。
函数签名: ```go func (l *RWKeyedLocker[K]) RLock(ctx context.Context, key K, fn func()) error ``` 示例:[运行](https://go.dev/play/p/ZrCr8sMo77T) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewRWKeyedLocker[string](2 * time.Second) // Simulate a key key := "resource_key" fn := func() { fmt.Println("Starting write operation...") // Simulate write operation, assuming it takes 2 seconds time.Sleep(200 * time.Millisecond) fmt.Println("Write operation completed!") } // Acquire the write lock and execute the operation ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() // Execute the lock operation with a 3-second timeout err := locker.RLock(ctx, key, fn) if err != nil { return } //output: //Starting write operation... //Write operation completed! } ``` ### LockLock为指定的键获取锁并执行提供的函数。
函数签名: ```go func (l *RWKeyedLocker[K]) Lock(ctx context.Context, key K, fn func()) error ``` 示例:[运行](https://go.dev/play/p/WgAcXbOPKGk) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := NewRWKeyedLocker[string](2 * time.Second) // Simulate a key key := "resource_key" fn := func() { fmt.Println("Starting write operation...") // Simulate write operation, assuming it takes 2 seconds time.Sleep(200 * time.Millisecond) fmt.Println("Write operation completed!") } // Acquire the write lock and execute the operation ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() // Execute the lock operation with a 3-second timeout err := locker.Lock(ctx, key, fn) if err != nil { return } //output: //Starting write operation... //Write operation completed! } ``` ### NewTryKeyedLocker创建一个TryKeyedLocker实例,TryKeyedLocker是KeyedLocker的非阻塞版本。
函数签名: ```go func NewTryKeyedLocker[K comparable]() *TryKeyedLocker[K] ``` 示例:[运行](https://go.dev/play/p/VG9qLvyetE2) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewTryKeyedLocker[string]() key := "resource_key" if locker.TryLock(key) { fmt.Println("Lock acquired") time.Sleep(1 * time.Second) // Unlock after work is done locker.Unlock(key) fmt.Println("Lock released") } else { fmt.Println("Lock failed") } //output: //Lock acquired //Lock released } ``` ### TryLockTryLock尝试获取指定键的锁。如果锁成功获取,则返回true,否则返回false。
函数签名: ```go func (l *TryKeyedLocker[K]) TryLock(key K) bool ``` 示例:[运行](https://go.dev/play/p/VG9qLvyetE2) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewTryKeyedLocker[string]() key := "resource_key" if locker.TryLock(key) { fmt.Println("Lock acquired") time.Sleep(1 * time.Second) // Unlock after work is done locker.Unlock(key) fmt.Println("Lock released") } else { fmt.Println("Lock failed") } //output: //Lock acquired //Lock released } ``` ### Unlock释放指定键的锁。
函数签名: ```go func (l *TryKeyedLocker[K]) Unlock(key K) ``` 示例:[运行](https://go.dev/play/p/VG9qLvyetE2) ```go package main import ( "fmt" "github.com/duke-git/lancet/v2/concurrency" ) func main() { locker := concurrency.NewTryKeyedLocker[string]() key := "resource_key" if locker.TryLock(key) { fmt.Println("Lock acquired") time.Sleep(1 * time.Second) // Unlock after work is done locker.Unlock(key) fmt.Println("Lock released") } else { fmt.Println("Lock failed") } //output: //Lock acquired //Lock released } ```