Как создать динамический конвейерный маршрут в Go
5 мая 2022 г.После просмотра нескольких обучающих видеороликов о Go мне стало интересно, можно ли создать конвейер с динамическими маршрутами. Вдохновленный шаблоном проектирования Builder и дополнительным шаблоном в Go, я придумал, как это реализовать.
Как это сделать ?
Представьте, что мы на автомобильном заводе, одна модель автомобиля имеет несколько типов. При производстве автомобиля одной и той же модели будут одни и те же производственные этапы, такие как изготовление шасси и кузова, затем каждому типу будет добавлен свой набор функций. Конвейер, который мы создадим, имеет блок-схему, как показано ниже, после конвейера «Body» автомобиль можно построить напрямую или добавить функции в соответствии с его типом.
Пакет конвейера
Сначала мы создадим структуру автомобиля, которая имеет несколько полей, таких как база, кузов, функция A, функция B и функция C. После этого мы создадим несколько методов для заполнения полей.
```иди
var Process = func(channel chan CarBuilder) func(builder CarBuilder) {
return func(строитель *CarBuilder) {
канал <- строитель
введите функцию NextProcess (построитель *CarBuilder)
введите структуру CarBuilder {
автомобиль
Следующий []СледующийПроцесс
func (c *CarBuilder) nextProcess() {
следующий := c.Next[0]
c.Следующий = c.Следующий[1:]
следующий (с)
func (c *CarBuilder) Построить () автомобиль {
вернуть c.car
После этого мы определяем переменную с именем «Процесс», вдохновленную необязательным шаблоном, и структура «CarBuilder» становится конструктором для автомобиля, содержащим поля автомобиля и список функций, которые мы хотим добавить. Затем создайте метод «nextProcess», чтобы перейти к следующему конвейеру, и метод «Build», чтобы вернуть построенный нами автомобиль.
```иди
var Process = func(channel chan CarBuilder) func(builder CarBuilder) {
return func(строитель *CarBuilder) {
канал <- строитель
введите функцию NextProcess (построитель *CarBuilder)
введите структуру CarBuilder {
автомобиль
Следующий []СледующийПроцесс
func (c *CarBuilder) nextProcess() {
следующий := c.Next[0]
c.Следующий = c.Следующий[1:]
следующий (с)
func (c *CarBuilder) Построить () автомобиль {
вернуть c.car
Последний этап — определение конвейеров. Мы создадим 5 конвейеров, а именно «BaseBuilder», «BodyBuilder», «FeatureABuilder», «FeatureBBuilder» и «FeatureCBuilder», которые служат для создания основы модели автомобиля или добавления функций.
```иди
func BaseBuilder(channel <-chan CarBuilder, nextChannel chan<- CarBuilder) {
за {
carBuilder := <-канал
carBuilder.setBase(истина)
следующий канал <- carBuilder
func BodyBuilder(канал <-chan *CarBuilder) {
за {
carBuilder := <-канал
carBuilder.setBody (истина)
carBuilder.nextProcess()
func FeatureABuilder(канал <-chan *CarBuilder) {
за {
carBuilder := <-канал
carBuilder.setFeatureA (истина)
carBuilder.nextProcess()
func FeatureBBuilder(канал <-chan *CarBuilder) {
за {
carBuilder := <-канал
carBuilder.setFeatureB (истина)
carBuilder.nextProcess()
func FeatureCBuilder(канал <-chan *CarBuilder) {
за {
carBuilder := <-канал
carBuilder.setFeatureC(истина)
carBuilder.nextProcess()
Основная функция
Чтобы использовать его в основной функции (main.go), сначала мы определяем «группу ожидания», чтобы дождаться завершения всех процессов, и канал для каждого конвейера с большим буфером для ускорения :D
```иди
var wg sync.WaitGroup
baseChan := make(chan *pipe.CarBuilder, 1000)
bodyChan := make(chan *pipe.CarBuilder, 1000)
featureAChan := make(chan *pipe.CarBuilder, 1000)
featureBChan := make(chan *pipe.CarBuilder, 1000)
featureCChan := make(chan *pipe.CarBuilder, 1000)
buildChan := make(chan *pipe.CarBuilder, 1000)
Также подготовьте список типов автомобилей, которые нам нужны, и какие функции доступны в этих типах, чтобы облегчить производство автомобилей в больших масштабах. Слайс «NextProcess» содержит каналы, представляющие функции, необходимые для создания типа.
```иди
typeStandard := []pipe.NextProcess{
труба.Процесс(buildChan),
типA := []pipe.NextProcess{
pipe.Process(featureAChan),
pipe.Process(featureCChan),
труба.Процесс(buildChan),
typeB := []pipe.NextProcess{
pipe.Process(featureAChan),
pipe.Process(featureBChan),
труба.Процесс(buildChan),
типC := []pipe.NextProcess{
pipe.Process(featureBChan),
pipe.Process(featureCChan),
труба.Процесс(buildChan),
typeFullFeature := []pipe.NextProcess{
pipe.Process(featureAChan),
pipe.Process(featureBChan),
pipe.Process(featureCChan),
труба.Процесс(buildChan),
возможности := [][]pipe.NextProcess{
типСтандартный, типA, типB, типC, типFullFeature,
После этого определите желаемый рабочий пул, я использую 4 для каждого конвейера, потому что нет значительного увеличения при использовании большего количества (на моем устройстве). Мы также можем определить счетчик автомобилей, чтобы определить, сколько автомобилей было произведено.
```иди
var carCount int64
для я := 1; я <= 4; я++ {
go pipe.BaseBuilder (baseChan, bodyChan)
go pipe.BodyBuilder(bodyChan)
go pipe.FeatureABuilder(featureAChan)
go pipe.FeatureBBuilder(featureBChan)
go pipe.FeatureCBuilder(featureCChan)
иди функ () {
за {
readyToBuild := <-buildChan
readyToBuild.Build ()
wg.Готово()
atomic.AddInt64(&carCount, 1)
Определите, сколько автомобилей мы хотим построить и их тип, в данном случае мы построим 100000 автомобилей.
```иди
var testBuilds []pipe.CarBuilder
для я := 0; я < 1000000; я++ {
testBuilds = добавить (testBuilds, pipe.CarBuilder {
Далее: характеристики[i%5],
Наконец, поместите автомобили, которые мы определили выше, один за другим в первый конвейер «BaseBuilder», и пусть произойдет волшебство :grin:
```иди
отложить func() func() {
начало := время.Сейчас()
return func() { fmt.Println(time.Since(start), carCount)}
для _, testBuild := диапазон testBuilds {
WG.Добавить(1)
т := testBuild
baseChan <- &t
РГ.Подождите(
Что является ключом к созданию динамического маршрута конвейера в go?
Ключ находится в переменной «Process» и методе «nextProcess». В переменной процесса мы можем ввести канал конвейера, который мы хотим посетить, в то время как метод «nextProcess» передаст указатель CarBuilder в переменную «Процесс», что означает, что он отправляет указатель CarBuilder на следующий конвейер.
```иди
var Process = func(channel chan CarBuilder) func(builder CarBuilder) {
return func(строитель *CarBuilder) {
канал <- строитель
введите функцию NextProcess (построитель *CarBuilder)
введите структуру CarBuilder {
автомобиль
Следующий []СледующийПроцесс
func (c *CarBuilder) nextProcess() {
следующий := c.Next[0]
c.Следующий = c.Следующий[1:]
следующий (с)
func (c *CarBuilder) Построить () автомобиль {
вернуть c.car
Я надеюсь, что некоторые из вас найдут это полезным. Если вам интересно увидеть весь исходный код, вы можете найти его на https://github.com/yudaph/dynamic-pipeline.
Не стесняйтесь оставлять предложения или критические замечания в разделе комментариев!
Спасибо!
Также опубликовано [здесь] (https://medium.com/@yudaph/dynamic-pipeline-route-in-go-c73a9df991c0).
Оригинал