2017-05-30 10 views
0

私はメモリキャッシュとチャネルとして同期マップを使用して同期アクセスを保証しています。マップを同期させるためにチャネルを使用するより良い方法はありますか?

私の「セッション」のパッケージには、キャッシュを定義していますマップ[文字列] * SessionDataに

SessionDataには、コードに見られるように、他のアクセス機能と一緒に、またパッケージで定義された構造体です。

GetWebPage(rw http.ResponseWriter, req *http.Request) { 
var sd *session.SessionData 
var sessTkn string 

cookie, err := req.Cookie("sesstoken") 

if err == nil { // cookie found 
    sessTkn = cookie.Value 
    // Check for cache entry for this token, 
    // using a channel to protect the map and return 
    // a pointer to the cached data if it exists 
    sdc := make(chan *session.SessionData, 1) 
    go session.GetSessionFromCache(sessTkn, sdc) 
    sd = <-sdc 

    if sd == nil { // sessTkn not in the cache 

     // This is test data to simplify example 
     sv := make([]string, 4) 
     sv[0] = sessTkn 
     iv := make([]int, 3) 
     iv[0] = 100 
     iv[1] = 1000 

     sdc := make(chan *session.SessionData, 1) 
     go session.NewSessionData(sv, iv, false, false, sdc) 
     session.SC[sessTkn] = <-sdc 
    } 

// Is this necessary? Is there a better way? 
// ---------------------------------------  
    if sd == nil { 
     sdc = make(chan *session.SessionData, 1) 
     go session.GetSessionFromCache(sessTkn, sdc) 
     sd = <-sdc  
    } 
// ---------------------------------------  

    fmt.Println(sd) // just to prove that it works in both cases 
} 
// The rest of the handler code follows 
+0

同期に使用できるアクセス[移動中セマフォパッケージ]の提案について(https://github.com/kamilsk/semaphore) –

+0

@Hamza感謝を確保するために。私の場合、汎用セマフォは通信能力を犠牲にします(チャネル上で型付きデータを送受信します)。望ましい副作用として、チャネルはマップへのアクセスをブロックし、非同期アクセスを保証します。いずれのアクセス機能も「重労働」とはみなされません。コードは機能しています。私の唯一の関心事は、新しいエントリがマップに追加されたことを確認するために必要な繰り返しです。 – emadera52

答えて

4

マップを保護するためにmutexを使用してください。ミューテックスは、チャネル&のゴルーチンを使用してリソースを保護するよりも、しばしば単純です。

var (
    mu sync.Mutex 
    cache = make(map[string]*SessionData) 
) 

func GetSessionFromCache(sessTkn string) *SessionData { 
    mu.Lock() 
    defer mu.Unlock() 
    sd := cache[sessTkn] 
    if sd != nil { 
     return sd 
    } 
    sd := &SessionData{ 
    // initialize new value here 
    } 
    cache[sessTkn] = sd 
    return sd 
} 

このようにそれを使用してください:この特定のケースのためのチャネルを使用して

sd := session.GetSessionFromCache(sessTkn) 
+0

ありがとうございます。私は同期のためにミューテックスを使う計画を始めました。その後、特にデータ値を共有する場合、チャネルを使用する上位レベルのアプリケーションの方が優れていることがわかりました。私は明らかに誤解しました。計画A.に戻る – emadera52

1

は追加の利点を持っていません。それについて考えると、新しいチャンネルを作成しても、マップにアクセスできるゴルーチンは1つだけです。ここに並行処理の利点がないので、sync.Mutexを使用してください。

package session 

import "sync" 

var cache = struct { 
    sync.Mutex 
    list map[string]*SessionData 
}{ 
    list: make(map[string]*SessionData), 
} 

func GetSessionFromCache(token string) *SessionData { 
    cache.Lock() 
    defer cache.Unlock() 
    return cache.list[token] 
} 

次に、新しいゴルーチンの必要はありません。ちょうどそれを直接呼びます。

sd := session.GetSessionFromCache(sessTkn) 
+0

チャンネルが行く方法ではない理由についての追加情報をありがとう。私は、チャンネルが何をしているのか、その使用が適切であるのかを完全に理解するために、さらに研究を行う必要があります。 – emadera52

関連する問題