2017-07-17 6 views
0

私はすべての単一のHTTP GETリクエストで呼び出される関数を持っています。この関数はファイルを読み込み、そのファイルの内容に何らかの処理を行い、それらの内容のバイトスライスを返します。このバイトのスライスは、HTTP応答ライターへの応答本文として書き込まれます。ファイルからゴングを読む - ロックするのは安全ですか?

複数のHTTP要求が同じファイルを読み込もうとした場合にロックを防止するために、この関数の任意のステップにmutexを使用する必要がありますか?もしそうなら、私は実際にそれに書き込むのではなく、その内容のコピーを作成しているので、ファイルの読み込みをロックするシンプルなRWMutexで十分でしょうか?ここで

が関数である:

// prepareIndex will grab index.html and add a nonce to the script tags for the CSP header compliance. 
func prepareIndex(nonce string) []byte { 
    // Load index.html. 
    file, err := os.Open("./client/dist/index.html") 
    if err != nil { 
     log.Fatal(err) 
    } 

    // Convert to goquery document. 
    doc, err := goquery.NewDocumentFromReader(file) 
    if err != nil { 
     fmt.Println(err) 
    } 

    // Find all script tags and set nonce. 
    doc.Find("body > script").SetAttr("nonce", nonce) 

    // Grab the HTML string. 
    html, err := doc.Html() 
    if err != nil { 
     fmt.Println(err) 
    } 

    return []byte(html) 
} 

私も一度だけと、メイン開始ファイルのロードと思ったが、私は最初の要求は、データと後続の要求は何も見なかった見ることができた問題を抱えていました。おそらく、私がファイルを読んでいる間のエラー。しかし、私は実際には私の現在のアプローチを好む。なぜなら、index.htmlに何らかの変更があったとしても、それらを実行可能ファイルを再起動することなくすぐにユーザーに永続させたいからです。

+1

https://godoc.org/github.com/fsnotify/fsnotifyあなたは、このレポhttps://github.com/nightlyone/lockfileをチェックしましたか? –

答えて

1

ファイルを変更する場合は、ミューテックスが必要です。 RWMutexは正常に動作するはずです。あなたはちょうどそれを読んでいるように見えます。その場合、ロック動作や破損は見られません。

同じファイルハンドルから2回目に読み取ったデータがなかったのは、2回目の読み込みを開始するときにファイルの最後にあることです。内容をもう一度読むには、seekに戻って0をオフセットする必要があります。

+0

ああ、私は今、説明のおかげで見る!それは今意味があります...そして、最初の部分については、はい、私はそれを読んだ後でファイルを変更していません。内容のクローンが作成され、クローンは変更されます(ただし、ロックされていても安全です)。 読んだ後にファイルを閉じる必要がありますか? – Lansana

+0

複数のゴルーチンが同時にファイルを読み書きしている場合は、シーク方式が問題になることに注意してください。起動時にファイルを '[] byte 'でロードすることをお勧めします。これはパフォーマンスの向上をもたらし、ディスク上のファイルの変更について心配する必要はありません。 また、ミューテックスを使用してファイルをロックすると、自分のプログラムによって変更されているファイルから保護されます。別のプログラムがファイルを変更しても、問題は発生します。 – yazgazan

2

RWMutexを使用しても、別のプログラムによって変更されているファイルから保護することはできません。最高のオプションは、起動時に[]byteにファイルをロードし、goquery.NewDocumentFromReaderを使用するたびに"bytes".Bufferをインスタンス化することです。変更内容をユーザーに伝えるには、fsnotify [1]を使用してファイルの変更を検出し、必要に応じてキャッシュされたファイル([]byte)を更新します(その操作にはRWMutexが必要です)。例えば

type CachedFile struct { 
    sync.RWMutex 
    FileName string 
    Content []byte 
    watcher *fsnotify.Watcher 
} 

func (c *CachedFile) Buffer() *bytes.Buffer { 
    c.RLock() 
    defer c.RUnlock() 
    return bytes.NewBuffer(c.Content) 
} 

func (c *CachedFile) Load() error { 
    c.Lock() 
    content, err := ioutil.ReadAll(c.FileName) 
    if err != nil { 
     c.Unlock() 
     return err 
    } 
    c.Content = content 
    c.Unlock() 
} 

func (c *CachedFile) Watch() error { 
    var err error 

    c.watcher, err = fsnotify.NewWatcher() 
    if err != nil { 
     return err 
    } 

    go func() { 
     for ev := range c.watcher.Events { 
      if ev.Op != fsnotify.Write { 
       continue 
      } 
      err := c.Load() 
      if err != nil { 
       log.Printf("loading %q: %s", c.FileName, err) 
      } 
     } 
    }() 

    err = c.watcher.Add(c.FileName) 
    if err != nil { 
     c.watcher.Close() 
     return err 
    } 

    return nil 
} 

func (c *CachedFile) Close() error { 
    return c.watcher.Close() 
} 

[1]

+0

ニースの答え!非常によく説明されています。私は今日後でこれをテストし、そのコンセプトが私にとってうまくいくかどうかを受け入れます。 – Lansana

関連する問題