3

ファイルのリストを調べて、それらの 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.ReadFiledeferdeferReadFile()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 個のファイル記述子が開かれるためです。;)deferUnzip()

上記のように deferredCloseを明示的に置き換えましたClose()が、同じ「開いているファイルが多すぎます」というエラーが引き続き発生します。変更した Unzip 関数に問題はありますか?

更新 # 2 おっと、私はこれを Heroku で実行していましたが、ずっと間違ったアプリに変更をプッシュしていました。得られた教訓: heroku toolbelt でターゲット アプリを確認します。

https://gist.github.com/hnaohiro/4572580からの解凍コードは、すべてのファイルが処理されるまでファイルを閉じないため、機能しません

上記の明示的なクローズを使用した私の解凍コードは機能し、@peterSOの回答の遅延バージョンも機能します。

4

1 に答える 1