У вас заканчиваются системные ресурсы, потому что вы используете слишком много файловых дескрипторов, не выпуская их достаточно. Вы должны ограничить параллелизм в своей программе.
Для этого вы можете иметь буферный канал, который действует как счетный семафор.
sem := make(chan struct{}, 12) // 12 is the maximum number of
// concurrent processes that may run at any time
Теперь вы можете модифицировать свой метод, как:
func main() {
var wg sync.WaitGroup
wg.Add(1024 * 1024)
for i := 0; i < (1024 * 1024); i++ {
go func(index int) {
// if there are already 12 goroutines running, below send will block
// and a new file wont be open
sem <- struct{}{}
// once this goroutine finishes, empty the buffer by one
// so the next process may start (another goroutine blocked on
// above send will now be able to execute the statement and continue)
defer func() { <-sem }()
// wg.Done must be deferred after a read from sem so that
// it executes before the above read
defer wg.Done()
if f, e := os.Open(strconv.Itoa(index)); e != nil {
// handle file open failure
return
}
defer f.Close()
// handle open file
}(i)
}
wg.Wait()
close(sem)
}
Использование wg.Done
также неправильно. Читайте об этом here
(Обратите внимание, что этот код, чтобы дать общее представление о таком роде проблемы Вы можете также обратиться к этому вопросу на рабочий пример:. Go worker pool with repetitive queue structure
ответ не идет связан, но читать man-страница для 'ulimit'. Однако - у вас код имеет две катастрофические ошибки, посмотрите, можете ли вы их обнаружить. И b. Кроме того, вы пытаетесь открыть 1M-файлы одновременно, если у вас нет массивного RAID массив это нецелесообразно –
Какая у вас ОС, это Unix/Linux? – kopiczko
ulimit - не лучшее решение. Я бы предпочел иметь только ограниченное количество goroutines, которые открывают файлы и обрабатывают их (возможно, 500 параллельных открытых файлов) И каждый горутин должен выбирать входы с того же канала, открывает t он записывает, читает и закрывает его, и отправляет результат обратно на другой канал. Этот второй канал должен быть частью запроса. И каждый, кто должен использовать такой goroutine, должен создать этот канал, отправить запрос и ждать результата. Вы понимаете, или вам нужен пример? – lofcek