2017-02-05 17 views
-2

参照渡しの同じ変数を変更する複数のゴルーチンを実行しようとしています。Golang複数のゴルーチンが同じ変数を参照で共有する

しかし、私はこれを実装した方法が機能的に間違っていると確信しています。私のテストでは動作しているように見えますが、第2のゴルーチンが最初のゴルーチンよりも実行にかなり長い時間がかかる場合、最初のゴルーチンが完了すると、このパターンが親関数を終了させるという感じがします。

あなたのご意見・ご提案・アドバイスをお待ちしております。

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(`[email protected]+`).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 
    } 
} 
+0

を上記のコードを書くための慣用的な方法は、値を返す単純な関数としてvalidatePasswordとvalidateUsernameを書くことです。ゴルーチンはここでは何の価値も提供していません。 –

答えて

2

単純な検証を実行するには確かにゴルーチンが必要ですか? とにかく、あなたが書いたコードは、goroutinesを使用していますが、並列では実行されていません。

あなたのコードで何が起こっているのですか: バッファされていないチャネルを作成し、それにCredentialResponse変数を入れます。 次に、1つのゴルーチン(いずれか2つ)が変数をチャネルから読み込み、いくつかのアクションを実行し、変数をチャネルに戻します。 最初のゴルーチンはいくつかのアクションを実行していましたが、2番目のアクションはチャンネルからの値を待っていました。

だからあなたのコードは、ゴルーチンを使用していますが、それはほとんどの並列と呼ばれることができません。

データの妥当性を確認するために重い操作が必要な場合は、io opsまたはCPUを使用することができますが、CPUの場合は、GOMAXPROCS> 1を指定する必要があります。

私は、検証のためのゴルーチンを使用したいと思いますならば、私はそれのようになめらかに書かれていると思います:

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 
    } 

    // ... 
} 
+2

JFTRでは、最近、GOMAXPROCSはプログラム起動時のコア数(OSによって報告された「仮想CPU」)に等しい。本当の問題は、ユーザー名とパスワードの検証が、goroutinesを作成して同期させるコストを上回るリソースを消費しているかどうかです。はい、goroutinesを作成することは、OSレベルのスレッドと比較して汚いですが、このコストはそれにもかかわらずゼロではありません。 – kostix

関連する問題