练习代码push
This commit is contained in:
commit
9a81b89885
96
cyclic_barrier/h2o.go
Normal file
96
cyclic_barrier/h2o.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package cyclic_barrier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/marusama/cyclicbarrier"
|
||||||
|
"golang.org/x/sync/semaphore"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
H2OHydrogenNum = 2 // 氢原子数量
|
||||||
|
H2OOxygenNum = 1 // 氧原子数量
|
||||||
|
)
|
||||||
|
|
||||||
|
// H2O 水分子结构体
|
||||||
|
type H2O struct {
|
||||||
|
semaH *semaphore.Weighted
|
||||||
|
semaO *semaphore.Weighted
|
||||||
|
cb cyclicbarrier.CyclicBarrier
|
||||||
|
wg sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewH2O() *H2O {
|
||||||
|
return &H2O{
|
||||||
|
semaH: semaphore.NewWeighted(H2OHydrogenNum), // 氢原子的信号量
|
||||||
|
semaO: semaphore.NewWeighted(H2OOxygenNum), // 氧原子的信号量
|
||||||
|
cb: cyclicbarrier.New(H2OHydrogenNum + H2OOxygenNum), // 循环栅栏,用来控制合成
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *H2O) hydrogen(releaseHydrogen func()) {
|
||||||
|
if err := h.semaH.Acquire(context.Background(), 1); err != nil { // 占用氢原子空槽
|
||||||
|
fmt.Println("Hydrogen Acquire err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseHydrogen()
|
||||||
|
if err := h.cb.Await(context.Background()); err != nil { // 等待栅栏放行
|
||||||
|
fmt.Println("Hydrogen Await err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.semaH.Release(1) // 释放氢原子空槽
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *H2O) oxygen(releaseOxygen func()) {
|
||||||
|
if err := h.semaO.Acquire(context.Background(), 1); err != nil { // 占用氧原子空槽
|
||||||
|
fmt.Println("Oxygen Acquire err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseOxygen()
|
||||||
|
if err := h.cb.Await(context.Background()); err != nil { // 等待栅栏放行
|
||||||
|
fmt.Println("Oxygen Await err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.semaO.Release(1) // 释放氧原子空槽
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *H2O) Gen(num uint) <-chan string {
|
||||||
|
// 计算总共需要生成的原子数量
|
||||||
|
sum := H2OHydrogenNum + H2OOxygenNum
|
||||||
|
numInt := int(num)
|
||||||
|
// 用来存放生成的原子
|
||||||
|
ch := make(chan string, numInt*sum)
|
||||||
|
releaseHydrogen := func() {
|
||||||
|
ch <- "H"
|
||||||
|
}
|
||||||
|
releaseOxygen := func() {
|
||||||
|
ch <- "O"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 WaitGroup 等待所有的 goroutine 完成
|
||||||
|
h.wg.Add(numInt * sum)
|
||||||
|
for i := 0; i < numInt*H2OHydrogenNum; i++ {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
||||||
|
h.hydrogen(releaseHydrogen)
|
||||||
|
h.wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
for i := 0; i < numInt*H2OOxygenNum; i++ {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
|
||||||
|
h.oxygen(releaseOxygen)
|
||||||
|
h.wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
h.wg.Wait()
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
24
cyclic_barrier/h2o_test.go
Normal file
24
cyclic_barrier/h2o_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package cyclic_barrier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestH2O(t *testing.T) {
|
||||||
|
h2o := NewH2O()
|
||||||
|
ch := h2o.Gen(10)
|
||||||
|
|
||||||
|
result := make([]string, 0, 10)
|
||||||
|
molecular := make([]string, 0, 3)
|
||||||
|
for c := range ch {
|
||||||
|
molecular = append(molecular, c)
|
||||||
|
if len(molecular) == 3 {
|
||||||
|
sort.Strings(molecular)
|
||||||
|
result = append(result, molecular[0]+molecular[1]+molecular[2])
|
||||||
|
molecular = molecular[:0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(result)
|
||||||
|
}
|
9
go.mod
Normal file
9
go.mod
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
module go-study
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/brildum/testify v0.0.0-20151105045740-d05693e2e501 // indirect
|
||||||
|
github.com/marusama/cyclicbarrier v1.1.0 // indirect
|
||||||
|
golang.org/x/sync v0.5.0 // indirect
|
||||||
|
)
|
6
go.sum
Normal file
6
go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
github.com/brildum/testify v0.0.0-20151105045740-d05693e2e501 h1:ZWEmkmb/iJoRKLR0YuRP9wnEeF54NT3iUiGNTm/VQrs=
|
||||||
|
github.com/brildum/testify v0.0.0-20151105045740-d05693e2e501/go.mod h1:Zpjn5ClomJALLjz5sjBsNW79y3MarfpDcZaSJqbsIwk=
|
||||||
|
github.com/marusama/cyclicbarrier v1.1.0 h1:ol/AG+sjvh5yz832avbNjaowoerBuD3AgozxL+aD9u0=
|
||||||
|
github.com/marusama/cyclicbarrier v1.1.0/go.mod h1:5u93l83cy51YXdz6eKq6kO9+9mGAooB6DHMAxcSuWwQ=
|
||||||
|
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||||
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
71
observer/observer.go
Normal file
71
observer/observer.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package observer
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
// Subject 被观察者
|
||||||
|
type Subject struct {
|
||||||
|
observers []Observer
|
||||||
|
in chan any
|
||||||
|
}
|
||||||
|
|
||||||
|
// Observer 观察者 chan
|
||||||
|
type Observer chan any
|
||||||
|
|
||||||
|
// NewSubject 获取被观察者实例
|
||||||
|
func NewSubject() Subject {
|
||||||
|
return Subject{in: make(chan any)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach 观察者绑定
|
||||||
|
func (s *Subject) Attach(observer ...Observer) {
|
||||||
|
s.observers = append(s.observers, observer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach 观察者解绑
|
||||||
|
func (s *Subject) Detach(observer Observer) {
|
||||||
|
for i, obs := range s.observers {
|
||||||
|
if obs == observer {
|
||||||
|
s.observers = append(s.observers[:i], s.observers[i+1:]...)
|
||||||
|
close(observer)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify 通知观察者
|
||||||
|
func (s *Subject) Notify(data any) {
|
||||||
|
go s.fanOut(s.in, s.observers)
|
||||||
|
s.in <- data
|
||||||
|
}
|
||||||
|
|
||||||
|
// fanOut 扇出模式实现
|
||||||
|
func (s *Subject) fanOut(ch <-chan interface{}, out []Observer) {
|
||||||
|
var cases []reflect.SelectCase
|
||||||
|
// 添加输入 chan 的 reflect.SelectCase
|
||||||
|
cases = append(cases, reflect.SelectCase{
|
||||||
|
Dir: reflect.SelectRecv,
|
||||||
|
Chan: reflect.ValueOf(ch),
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
// 退出时关闭所有的输出 chan
|
||||||
|
for _, o := range out {
|
||||||
|
close(o)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, value, ok := reflect.Select(cases) // 从输入 chan 中读取数据
|
||||||
|
if !ok {
|
||||||
|
// 输入 channel 被关闭
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入 channel 接收到数据
|
||||||
|
for _, o := range out {
|
||||||
|
o <- value.Interface() // 放入到输出 chan 中,同步方式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
31
observer/observer_test.go
Normal file
31
observer/observer_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package observer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestObserver(t *testing.T) {
|
||||||
|
sendEmail := make(Observer)
|
||||||
|
notifyWelcome := make(Observer)
|
||||||
|
|
||||||
|
userRegister := NewSubject()
|
||||||
|
userRegister.Attach(sendEmail, notifyWelcome)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for data := range sendEmail {
|
||||||
|
fmt.Println("The send email service receive data: ", data)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for data := range notifyWelcome {
|
||||||
|
fmt.Println("The notify welcome service receive data: ", data)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
newUser1 := "fantasticbin"
|
||||||
|
newUser2 := "gan"
|
||||||
|
userRegister.Notify(newUser1)
|
||||||
|
userRegister.Notify(newUser2)
|
||||||
|
}
|
63
routine/pool.go
Normal file
63
routine/pool.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package routine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pool[T any] struct {
|
||||||
|
taskQueue chan T
|
||||||
|
taskFn func(T)
|
||||||
|
workers int
|
||||||
|
wg sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPool[T any](workers, capacity int, taskFn func(T)) *Pool[T] {
|
||||||
|
pool := &Pool[T]{
|
||||||
|
taskQueue: make(chan T, capacity),
|
||||||
|
taskFn: func(t T) {
|
||||||
|
defer func() {
|
||||||
|
// 处理协程运行中出现panic的情况
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Printf("Panic: %v\n %s", r, string(debug.Stack()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
taskFn(t)
|
||||||
|
},
|
||||||
|
workers: workers,
|
||||||
|
}
|
||||||
|
pool.wg.Add(workers)
|
||||||
|
|
||||||
|
return pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动任务
|
||||||
|
func (p *Pool[T]) Start() {
|
||||||
|
for i := 0; i < p.workers; i++ {
|
||||||
|
go func() {
|
||||||
|
defer p.wg.Done()
|
||||||
|
|
||||||
|
for {
|
||||||
|
task, ok := <-p.taskQueue
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.taskFn(task)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push 提交任务
|
||||||
|
func (p *Pool[T]) Push(task T) {
|
||||||
|
p.taskQueue <- task
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 挂起当前协程
|
||||||
|
func (p *Pool[T]) Wait() {
|
||||||
|
close(p.taskQueue)
|
||||||
|
p.wg.Wait()
|
||||||
|
}
|
32
routine/pool_test.go
Normal file
32
routine/pool_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package routine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/brildum/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPool(t *testing.T) {
|
||||||
|
num := runtime.NumCPU()
|
||||||
|
var sum atomic.Int32
|
||||||
|
pool := NewPool(num, num, func(num int32) {
|
||||||
|
if num < 0 {
|
||||||
|
panic("unable to handle negative numbers")
|
||||||
|
}
|
||||||
|
|
||||||
|
sum.Add(num)
|
||||||
|
})
|
||||||
|
pool.Start()
|
||||||
|
|
||||||
|
for i := int32(1000); i >= -1; i-- {
|
||||||
|
pool.Push(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.Wait()
|
||||||
|
|
||||||
|
if assert.Equal(t, int32(500500), sum.Load()) {
|
||||||
|
t.Log("the sum value is right")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user