Задать вопрос
@VictorOlegovich

Как правильно обрабатывать каналы в go?

Доброго времени суток.
Появилась проблема с параллельностью на го.
Хочу, чтобы мой валидатор валидировал данные параллельно с помощью каналов:
валидатор должен обойти каждую структуру в цикле и обработать её с помощью горутины.
Уже три дня пытаюсь обойти проблемы связанные с тем, что данный цикл не дорабатывает до конца, что в итоге приводит к тому, что не каждая структура обрабатывается. С каналами не очень дружу, к сожалению, т.к. в го сам недавно. Очень прошу помочь. Код ниже:

Тип структуры и её полей(всё крайне просто) :
type Struct struct {
	Name   string
	Fields []Field
}

type Field struct {
	Name, Type string
}


Код обработки структур:

package validator

import (
	"errors"
	c "github.com/victorolegovich/storage_generator/collection"
	p "github.com/victorolegovich/storage_generator/parser"
	"github.com/victorolegovich/storage_generator/types"
)

type errorType struct {
	section string
	error   string
}

type crossingChannels struct {
	ErrorChan          chan errorType
	RequiredStructChan chan string
}

func StructsValidation(Structs []c.Struct) error {
	var errorText string

	errs := map[string]string{}

	channels := crossingChannels{
		ErrorChan:          make(chan errorType),
		RequiredStructChan: make(chan string),
	}

	structsNames := ExtractStructsNames(Structs)

	for i := 0; i < len(Structs); i++ {
		go StructValidation(Structs[i], channels)

		result := <-channels.RequiredStructChan

		if !StructExist(structsNames, result) {
			errs[fieldsSection] += result + ": field type is not exist in this file\n"
		}
	}

	if len(errs) != 0 {
		for section, s := range errs {
			errorText += section + ":\n" + s
		}
	}

	return errors.New(errorText)
}

func ExtractStructsNames(Structs []c.Struct) (Names []string) {
	for _, Struct := range Structs {
		Names = append(Names, Struct.Name)
	}
	return Names
}

func StructExist(StructsNames []string, StructName string) bool {
	for _, SName := range StructsNames {
		if SName == StructName {
			return true
		}
	}
	return false
}

func StructValidation(Struct c.Struct, channels crossingChannels) {
	for _, Field := range Struct.Fields {
		FieldValidation(Field, channels)
	}
}

func FieldValidation(Field c.Field, channels crossingChannels) {
	typeVerify(Field, channels)
}

func typeVerify(Field c.Field, channels crossingChannels) {
	ftype := Field.Type

	if result, typename := isArray(ftype); result {
		if !types.IsSimpleType(typename) {
			channels.RequiredStructChan <- typename
		}
		return
	}

	if result, maptype := isMap(ftype); result {
		if !types.IsSimpleType(maptype.key) {
			channels.RequiredStructChan <- maptype.key
		}

		if !types.IsSimpleType(maptype.value) {
			channels.RequiredStructChan <- maptype.value
		}
		return
	}

	if !types.IsSimpleType(ftype) {
		if ftype != c.ComplicatedType {

			channels.RequiredStructChan <- ftype
			return
		}

		channels.ErrorChan <- errorType{
			section: typesSection,
			error:   ftype + " is complicated type",
		}
	}
	return
}


P.S. Пробовал вэйт группы, мьютексы, буферизировал каналы - ничто из этого у меня не получилось сделать правильно(
  • Вопрос задан
  • 208 просмотров
Подписаться 2 Средний 8 комментариев
Пригласить эксперта
Ответы на вопрос 1
index0h
@index0h
PHP, Golang. https://github.com/index0h
Если я правильно понял вашу задачу, делать сам валидатор на горутинах - не самая хорошая идея, вы только потеряете в производительности, да и гемора себе же добавите.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы