ファイルのリストを調べて、それらの xml データを構造体の配列にアンマーシャリングしていますrArray
。約18000ファイルを処理する予定です。約 1300 個のファイルが処理されると、プログラムがパニックになり、開いているファイルが多すぎると表示されます。処理するファイルの量を安全な量の 1000 に制限すると、プログラムはクラッシュしません。
ioutil.ReadFile
以下に示すように、ファイル データの読み取りに使用しています。
for _, f := range files {
func() {
data, err := ioutil.ReadFile("./" + recordDir + "/" + f.Name())
if err != nil {
fmt.Println("error reading %v", err)
return
} else {
if (strings.Contains(filepath.Ext(f.Name()), "xml")) {
//unmarshal data and put into struct array
err = xml.Unmarshal([]byte(data), &rArray[a])
if err != nil {
fmt.Println("error decoding %v: %v",f.Name(), err)
return
}
}
}
}()
}
Go が使用しているファイル記述子が多すぎるのか、それともファイルを十分に速く閉じていないのかはわかりません。
https://groups.google.com/forum/#!topic/golang-nuts/7yXXjgcOikMを読み、 http://golang.org/src/pkg/io/ioutil/ioutil.goioutil
でソースを表示した後、コードforは、ファイルを閉じるために使用することを示しています。呼び出し元の関数が返されたときに実行され、呼び出し元の関数です。この理解で正しいですか?また、コードの一部を関数でラップしようとしましたが、違いはありません。ioutil.ReadFile
defer
defer
ReadFile()
ioutil.ReadFile
私のulimit
は無制限に設定されています。
更新: 解凍機能中にファイルが多すぎるというエラーが実際に発生していると思います。
func Unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
panic(err)
}
path := filepath.Join(dest, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
f, err := os.OpenFile(
path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
panic(err)
}
_, err = io.Copy(f, rc)
if err != nil {
panic(err)
}
f.Close()
}
rc.Close()
}
r.Close()
return nil
}
私は最初にhttps://gist.github.com/hnaohiro/4572580Unzip
から関数を取得しましたが、さらに調べたところ、要点作成者の関数での の使用は、関数が返された後にのみファイルが閉じられるため、遅すぎるように見えました。 18000 個のファイル記述子が開かれるためです。;)defer
Unzip()
上記のように deferredClose
を明示的に置き換えましたClose()
が、同じ「開いているファイルが多すぎます」というエラーが引き続き発生します。変更した Unzip 関数に問題はありますか?
更新 # 2 おっと、私はこれを Heroku で実行していましたが、ずっと間違ったアプリに変更をプッシュしていました。得られた教訓: heroku toolbelt でターゲット アプリを確認します。
https://gist.github.com/hnaohiro/4572580からの解凍コードは、すべてのファイルが処理されるまでファイルを閉じないため、機能しません。
上記の明示的なクローズを使用した私の解凍コードは機能し、@peterSOの回答の遅延バージョンも機能します。