2016-08-08 5 views
1
package main 

import (
    "os" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    wg.Add(1024 * 1024) 
    for i := 0; i < (1024 * 1024); i++ { 
     go func(index int) { 
      if f, e := os.Open(i); e == nil { 
       //blah blah 
       f.Close() 
      } 
     }(i) 
    } 
    wg.Done() 
} 

При запуске программы появляется следующая ошибка. «open $ too many open files» Пожалуйста, сообщите нам, как устранить ошибку.golang too many open files in go function, goroutine

+8

ответ не идет связан, но читать man-страница для 'ulimit'. Однако - у вас код имеет две катастрофические ошибки, посмотрите, можете ли вы их обнаружить. И b. Кроме того, вы пытаетесь открыть 1M-файлы одновременно, если у вас нет массивного RAID массив это нецелесообразно –

+0

Какая у вас ОС, это Unix/Linux? – kopiczko

+0

ulimit - не лучшее решение. Я бы предпочел иметь только ограниченное количество goroutines, которые открывают файлы и обрабатывают их (возможно, 500 параллельных открытых файлов) И каждый горутин должен выбирать входы с того же канала, открывает t он записывает, читает и закрывает его, и отправляет результат обратно на другой канал. Этот второй канал должен быть частью запроса. И каждый, кто должен использовать такой goroutine, должен создать этот канал, отправить запрос и ждать результата. Вы понимаете, или вам нужен пример? – lofcek

ответ

4

У вас заканчиваются системные ресурсы, потому что вы используете слишком много файловых дескрипторов, не выпуская их достаточно. Вы должны ограничить параллелизм в своей программе.

Для этого вы можете иметь буферный канал, который действует как счетный семафор.

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

+0

У этого все еще есть две ошибки исходного вопроса: 1. Функция goroutine относится к 'i', а не к' index', которая передается ему, и приведет к открытию неправильных файлов (кроме того, что вы можете " t открывать целые числа в виде файлов). 2. все еще добавляя 1024 * 1024 к waitGroup при выполнении 'Done()' только один раз :) –

+0

Обновлена ​​ошибка 'index'. Благодарю. О 'wg.Done', что вы имеете в виду, что это делается только один раз? Каждый горутин должен сделать это один раз, и это то, что происходит. Не могли бы вы объяснить немного больше. – abhink

+0

нет, все в порядке, вы исправили его. В коде самого вопроса есть эта ошибка. –