go:Pipeline Pattern

项目结构:

image

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:07
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : config.go
*/
package config

import (
	"log"
	"os"
	"time"
)

const (
	Timeout        = 1 * time.Second
	RetryTimes     = 2
	MaxReworkCount = 2
	ProcessSleep   = 200 * time.Millisecond
)

var Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lmsgprefix)



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:08
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : model.go
*/
package model

type RawStone struct {
	SN     int
	Carat  float64
	Origin string
}

type CutDiamond struct {
	SN          int
	Carat       float64
	CutGrade    string
	ReworkCount int
}

type ClarityResult struct {
	SN      int
	Grade   string
	Pass    bool
	Diamond *CutDiamond
}

type ColorResult struct {
	SN      int
	Grade   string
	Pass    bool
	Diamond *CutDiamond
}

type QCMerged struct {
	SN      int
	Carat   float64
	Cut     string
	Clarity string
	Color   string
	PassAll bool
	Diamond *CutDiamond
}

type Inlaid struct {
	SN        int
	Metal     string
	QC        *QCMerged
	LaborCost float64
}

type Finished struct {
	SN    int
	Name  string
	Price float64
}

type SaleOrder struct {
	SN    int
	Name  string
	Price float64
}

type DefectItem struct {
	Item  any
	Stage string
	Err   string
}


/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:09
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : channel.go
*/
package core

import "sync"

const StopSignal = "__STOP__"

type Channel[T any] struct {
	ch chan T
}

func NewChannel[T any]() *Channel[T] {
	return &Channel[T]{ch: make(chan T, 10)}
}

func (c *Channel[T]) Send(item T) {
	c.ch <- item
}

func (c *Channel[T]) Recv() (T, bool) {
	v, ok := <-c.ch
	return v, ok
}

func (c *Channel[T]) Close() {
	close(c.ch)
}

func SplitStream[T any](src *Channel[T], dsts []*Channel[T], wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		item, ok := src.Recv()
		if !ok {
			for _, d := range dsts {
				d.Close()
			}
			return
		}
		for _, d := range dsts {
			d.Send(item)
		}
	}
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:39
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : metrics.go
*/
package core

import "sync"

type Metrics struct {
	Total   int
	Success int
	Fail    int
	Retry   int
}

var (
	stageMetrics = make(map[string]*Metrics)
	mu           sync.RWMutex
)

func InitStage(name string) {
	mu.Lock()
	defer mu.Unlock()
	if stageMetrics[name] == nil {
		stageMetrics[name] = &Metrics{}
	}
}

func IncTotal(name string) {
	mu.Lock()
	defer mu.Unlock()
	stageMetrics[name].Total++
}

func IncSuccess(name string) {
	mu.Lock()
	defer mu.Unlock()
	stageMetrics[name].Success++
}

func IncFail(name string) {
	mu.Lock()
	defer mu.Unlock()
	stageMetrics[name].Fail++
}

func IncRetry(name string) {
	mu.Lock()
	defer mu.Unlock()
	stageMetrics[name].Retry++
}

func GetMetrics() map[string]*Metrics {
	mu.RLock()
	defer mu.RUnlock()
	copy := make(map[string]*Metrics)
	for k, v := range stageMetrics {
		copy[k] = v
	}
	return copy
}


/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:40
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : stage.go
*/
package core

import (
	"godesginpattern/pipeline/config"
	"godesginpattern/pipeline/model"
	"time"
)

func RunStage[Tin, Tout any](
	name string,
	in *Channel[Tin],
	out *Channel[Tout],
	defect *Channel[*model.DefectItem],
	process func(Tin) (Tout, error),
) {
	config.Logger.Printf("【阶段启动】%s", name)
	InitStage(name)

	for {
		item, ok := in.Recv()
		if !ok {
			break
		}

		IncTotal(name)
		var res Tout
		var err error
		success := false

		for attempt := 0; attempt <= config.RetryTimes; attempt++ {
			res, err = process(item)
			if err == nil {
				success = true
				break
			}
			IncRetry(name)
			sn := getSN(item)
			config.Logger.Printf("【%s】SN:%d 第%d次失败: %v", name, sn, attempt+1, err)
			time.Sleep(100 * time.Millisecond)
		}

		if success {
			IncSuccess(name)
			out.Send(res)
		} else {
			IncFail(name)
			defect.Send(&model.DefectItem{
				Item:  item,
				Stage: name,
				Err:   err.Error(),
			})
		}
	}

	out.Close()
	config.Logger.Printf("【阶段结束】%s", name)
}

func getSN(v any) int {
	switch t := v.(type) {
	case *model.CutDiamond:
		return t.SN
	case *model.QCMerged:
		return t.SN
	case *model.Inlaid:
		return t.SN
	case *model.Finished:
		return t.SN
	default:
		return 0
	}
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:42
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : fork_join.go
*/
package core

import (
	"godesginpattern/pipeline/model"
	"sync"
)

func ForkBranch[Tin, Tout any](
	in *Channel[Tin],
	out *Channel[Tout],
	fn func(Tin) Tout,
	wg *sync.WaitGroup,
) {
	defer wg.Done()
	for {
		item, ok := in.Recv()
		if !ok {
			break
		}
		out.Send(fn(item))
	}
	out.Close()
}

func JoinMerger(
	clarityCh *Channel[*model.ClarityResult],
	colorCh *Channel[*model.ColorResult],
	out *Channel[*model.QCMerged],
	merge func(*model.CutDiamond, *model.ClarityResult, *model.ColorResult) *model.QCMerged,
) {
	clarityMap := make(map[int]*model.ClarityResult)
	colorMap := make(map[int]*model.ColorResult)

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		for {
			r, ok := clarityCh.Recv()
			if !ok {
				break
			}
			clarityMap[r.SN] = r
		}
	}()

	go func() {
		defer wg.Done()
		for {
			r, ok := colorCh.Recv()
			if !ok {
				break
			}
			colorMap[r.SN] = r
		}
	}()

	wg.Wait()

	for sn, cr := range clarityMap {
		if cc, ok := colorMap[sn]; ok {
			out.Send(merge(cr.Diamond, cr, cc))
		}
	}
	out.Close()
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:43
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : defect.go
*/
package core

import (
	"godesginpattern/pipeline/config"
	"godesginpattern/pipeline/model"
)

func DefectReworkConsumer(
	defectCh *Channel[*model.DefectItem],
	reworkCh *Channel[*model.CutDiamond],
) {
	config.Logger.Println("次品返工分拣中心启动")
	for {
		item, ok := defectCh.Recv()
		if !ok {
			break
		}

		diamond, ok := item.Item.(*model.CutDiamond)
		if !ok {
			continue
		}

		if diamond.ReworkCount < config.MaxReworkCount {
			diamond.ReworkCount++
			config.Logger.Printf("【返工】SN:%d 第%d次回流切割工序", diamond.SN, diamond.ReworkCount)
			reworkCh.Send(diamond)
		} else {
			config.Logger.Printf("【报废】SN:%d 超过最大返工次数", diamond.SN)
		}
	}
	reworkCh.Close()
}

  

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:45
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : services.go
*/
package service

import (
	"errors"
	"godesginpattern/pipeline/config"
	"godesginpattern/pipeline/model"
	"math/rand"
	"strconv"
	"time"
)

func CutStone(raw *model.RawStone) (*model.CutDiamond, error) {
	time.Sleep(config.ProcessSleep)
	grade := "VG"
	if raw.Carat >= 1.0 {
		grade = "EX"
	}
	return &model.CutDiamond{
		SN:       raw.SN,
		Carat:    raw.Carat,
		CutGrade: grade,
	}, nil
}

func CheckClarity(d *model.CutDiamond) *model.ClarityResult {
	time.Sleep(config.ProcessSleep)
	grades := []string{"VS1", "VS2", "SI1"}
	g := grades[rand.Intn(len(grades))]
	pass := g != "SI1" || d.Carat > 0.7
	return &model.ClarityResult{
		SN:      d.SN,
		Grade:   g,
		Pass:    pass,
		Diamond: d,
	}
}

func CheckColor(d *model.CutDiamond) *model.ColorResult {
	time.Sleep(config.ProcessSleep)
	grades := []string{"D", "G", "J"}
	g := grades[rand.Intn(len(grades))]
	pass := g == "D" || g == "G"
	return &model.ColorResult{
		SN:      d.SN,
		Grade:   g,
		Pass:    pass,
		Diamond: d,
	}
}

func MergeQC(d *model.CutDiamond, c *model.ClarityResult, co *model.ColorResult) *model.QCMerged {
	return &model.QCMerged{
		SN:      d.SN,
		Carat:   d.Carat,
		Cut:     d.CutGrade,
		Clarity: c.Grade,
		Color:   co.Grade,
		PassAll: c.Pass && co.Pass,
		Diamond: d,
	}
}

func Inlay(qc *model.QCMerged) (*model.Inlaid, error) {
	time.Sleep(config.ProcessSleep)
	if !qc.PassAll {
		return nil, errors.New("钻石质检未通过,禁止镶嵌加工")
	}
	metals := []string{"18K黄金", "PT950铂金", "S925银"}
	metal := metals[rand.Intn(len(metals))]
	return &model.Inlaid{
		SN:        qc.SN,
		Metal:     metal,
		QC:        qc,
		LaborCost: qc.Carat * 1200,
	}, nil
}

func Finish(in *model.Inlaid) (*model.Finished, error) {
	time.Sleep(config.ProcessSleep)
	cost := in.LaborCost + in.QC.Carat*8500
	price := cost * 1.75
	name := in.Metal + "钻戒-" + strconv.Itoa(in.SN)
	return &model.Finished{
		SN:    in.SN,
		Name:  name,
		Price: price,
	}, nil
}

func Sale(f *model.Finished) (*model.SaleOrder, error) {
	time.Sleep(config.ProcessSleep / 2)
	return &model.SaleOrder{
		SN:    f.SN,
		Name:  f.Name,
		Price: f.Price,
	}, nil
}



/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:45
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : factory.go
*/
package factory

import (
	"godesginpattern/pipeline/core"
	"godesginpattern/pipeline/model"
	"godesginpattern/pipeline/service"
	"sync"
)

func BuildPipeline(
	source *core.Channel[*model.RawStone], // 修复:输入改为 RawStone
) (*core.Channel[*model.SaleOrder], *sync.WaitGroup) {

	// 所有通道类型对齐
	rawIn := source
	cutOut := core.NewChannel[*model.CutDiamond]()

	clarityIn := core.NewChannel[*model.CutDiamond]()
	colorIn := core.NewChannel[*model.CutDiamond]()
	clarityOut := core.NewChannel[*model.ClarityResult]()
	colorOut := core.NewChannel[*model.ColorResult]()

	mergedOut := core.NewChannel[*model.QCMerged]()
	inlayOut := core.NewChannel[*model.Inlaid]()
	finishOut := core.NewChannel[*model.Finished]()
	saleOut := core.NewChannel[*model.SaleOrder]()
	defectCh := core.NewChannel[*model.DefectItem]()

	var wg sync.WaitGroup
	wg.Add(3)

	// 分流器:切割完成 → 分发给净度/颜色检测
	go core.SplitStream(cutOut, []*core.Channel[*model.CutDiamond]{clarityIn, colorIn}, &wg)

	// 并行质检分支
	go core.ForkBranch(clarityIn, clarityOut, service.CheckClarity, &wg)
	go core.ForkBranch(colorIn, colorOut, service.CheckColor, &wg)

	// 合并两路质检结果
	go core.JoinMerger(clarityOut, colorOut, mergedOut, service.MergeQC)

	// 流水线所有工序(类型 100% 匹配)
	go core.RunStage("1-原石切割", rawIn, cutOut, defectCh, service.CutStone)
	go core.RunStage("2-贵金属镶嵌", mergedOut, inlayOut, defectCh, service.Inlay)
	go core.RunStage("3-成品定价", inlayOut, finishOut, defectCh, service.Finish)
	go core.RunStage("4-销售出库", finishOut, saleOut, defectCh, service.Sale)

	// 次品返工
	go core.DefectReworkConsumer(defectCh, cutOut)

	return saleOut, &wg
}

  

调用:

/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:47
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : pipelinebll.go
*/
package bll

import (
	"godesginpattern/pipeline/config"
	"godesginpattern/pipeline/core"
	"godesginpattern/pipeline/factory"
	"godesginpattern/pipeline/model"
)

func PipelineMain() {
	config.Logger.Println("===== 企业级珠宝异步Pipeline启动(并行质检+次品返工)=====")

	// 输入通道:RawStone 原石(完全对齐)
	source := core.NewChannel[*model.RawStone]()

	raws := []*model.RawStone{
		{SN: 2001, Carat: 0.62, Origin: "南非"},
		{SN: 2002, Carat: 1.15, Origin: "博茨瓦纳"},
		{SN: 2003, Carat: 0.48, Origin: "俄罗斯"},
		{SN: 2004, Carat: 1.32, Origin: "南非"},
		{SN: 2005, Carat: 0.75, Origin: "澳大利亚"},
		{SN: 2007, Carat: 0.90, Origin: "纳米比亚"},
	}

	// 直接投放原石,不再提前切割
	for _, r := range raws {
		config.Logger.Printf("原料进料 SN:%d", r.SN)
		source.Send(r)
	}
	source.Close()

	// 启动流水线
	saleOut, wg := factory.BuildPipeline(source)

	// 消费销售结果
	count := 0
	for {
		order, ok := saleOut.Recv()
		if !ok {
			break
		}
		count++
		config.Logger.Printf("✅ 销售单据 SN:%d 售价:%.2f", order.SN, order.Price)
	}

	wg.Wait()
	config.Logger.Println("\n========== 流水线执行完成 ==========")
	config.Logger.Printf("总投入原石:%d件  成功销售:%d件", len(raws), count)
}

  

输出:

image

 

posted @ 2026-06-21 17:11  ®Geovin Du Dream Park™  阅读(3)  评论(0)    收藏  举报