Как создать динамический конвейерный маршрут в Go

Как создать динамический конвейерный маршрут в 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).



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE