Golang多个goroutine通过引用共享相同的变量

时间:2017-02-05 01:15:47

标签: go goroutine

我正在尝试运行多个goroutine来修改引用传递的同一个变量。

但我确信我实现这一点的方式在功能上是不正确的。即使它似乎在我的测试中工作,但我觉得这个模式会在第一个goroutine完成后结束父函数,如果第二个goroutine比第一个goroutine运行的时间要长得多。

我想要您的意见/建议。

package auth

import (
    "regexp"

    zxcvbn "github.com/nbutton23/zxcvbn-go"
    "golang.org/x/net/context"
)

type AuthService struct{}

func NewAuthService() *AuthService {
    return &AuthService{}
}

func (this *AuthService) ValidateCredentials(ctx context.Context, req *ValidateCredentialsRequest) (*ValidateCredentialsResponse, error) {
    c := make(chan *ValidateCredentialsResponse)

    go validatePassword(req.GetPassword(), c)
    go validateUsername(req.GetUsername(), c)

    c <- &ValidateCredentialsResponse{IsValid: true}

    return <-c, nil
}

func validateUsername(email string, c chan *ValidateCredentialsResponse) {
    for {
        res := <-c

        if email == "" {
            res.IsValid = false
            res.Username = "Please provide your email address."
        } else if len(email) > 128 {
            res.IsValid = false
            res.Username = "Email address can not exceed 128 characters."
        } else if !regexp.MustCompile(`.+@.+`).MatchString(email) {
            res.IsValid = false
            res.Username = "Please enter a valid email address."
        }

        c <- res
    }
}

func validatePassword(password string, c chan *ValidateCredentialsResponse) {
    for {
        res := <-c

        if password == "" {
            res.IsValid = false
            res.Password = "Please provide your password."
        } else {
            quality := zxcvbn.PasswordStrength(password, []string{})
            if quality.Score < 3 {
                res.IsValid = false
                res.Password = "Your password is weak."
            }
        }

        c <- res
    }
}

1 个答案:

答案 0 :(得分:2)

您确定需要goroutines来执行简单的验证吗? 无论如何,你编写的代码都使用了goroutine,但它们并没有并行运行。

您的代码中发生了什么: 您创建非缓冲通道并将CredentialResponse变量放入其中。 然后一个goroutine(两个中的任何一个)从通道读取变量,执行一些操作,并将变量放回通道。 虽然第一个goroutine正在做一些动作,但第二个只是等待来自频道的值。

所以你的代码使用了goroutines,但它很难被称为并行。

如果您需要一些繁重的操作来验证数据,您可能需要使用goroutine:io ops或CPU,但是在CPU的情况下,您需要指定GOMAXPROCS&gt; 1以获得一些性能提升。

如果我想使用goroutines进行验证,我会写出像这样的文字:

func validateCredentials(req *ValidateCredentialsRequest){
    ch := make(chan bool, 2)
    go func(name string){
    // ... validation code
        ch <- true // or false

    }(req.GetUsername())

    go func(pwd string){
    // ... validation code
        ch <- true // or false
    }(req.GetPassword())

    valid := true
    for i := 0; i < 2; i++ {
        v := <- result
        valid = valid && v
    }

    // ...
}