Ресурс исчерпан (слишком много открытых файлов) - PullRequest
2 голосов
/ 03 января 2012

У меня 5000 векторов, которые хранятся в 5000 файлах.Мне нужно найти их сумму.Тип DF2 является просто синонимом для Vector Double и создан как экземпляр Num.Поэтому я прочитал и проанализировал все эти файлы, чтобы вывести список [IO DF2] и сложил его:

getFinal :: IO DF2
getFinal = foldl1' (liftA2 (+)) $ map getDF2 [1..(sdNumber runParameters)]
    where getDF2 i = fmap parseDF2 $ readFile ("DF2/DF2_" ++ show i)

Однако я получаю сообщение об ошибке:

DF2: DF2/DF2_1022: openFile: resource exhausted (Too many open files)

Google обнаружил, что этот вопрос очень распространен:

Однако я не понял, в чем проблема с ленивым вводом-выводом.Если он ленивый, то почему он открывает файлы до того, как они понадобятся?Я также не понимал, как адаптировать элегантное решение от Duncan Coutts к моему делу.

1 Ответ

6 голосов
/ 03 января 2012

Дело не в том, что он открывает файлы до того, как они понадобятся;это то, что он не закрывает их, пока вы не форсируете всю строку.Простой способ обойти эту проблему - заставить всю строку сразу после ее прочтения;Так как Векторы строгие, самый простой способ сделать это - заставить Вектор быть оцененным после его анализа:

getFinal :: IO DF2
getFinal = foldl1' (liftA2 (+)) $ map getDF2 [1..(sdNumber runParameters)]
    where getDF2 i = readFile ("DF2/DF2_" ++ show i) >>= evaluate . parseDF2

Используется Control.Exception.evaluate ;вы можете думать о evaluate как о форсировании его аргумента и его возврате.Однако это работает только в том случае, если parseDF2 использует всю строку.

Более элегантным решением было бы полностью отказаться от ленивого ввода-вывода и использовать итерации или что-то в этом роде.Но это, вероятно, не стоит для такого простого варианта использования.

...