2016-10-30 1 views
6

Я не совсем уверен, что это 'func literal', таким образом, эта ошибка меня немного сбивает с толку. Я думаю, что вижу проблему - я ссылаюсь на переменную значения диапазона изнутри новой процедуры go, поэтому значение может измениться в любое время и не быть тем, что мы ожидаем. Каков наилучший способ решить проблему?Перейдите в переменную ветеринга, захваченную func literal при использовании процедуры go внутри внутри каждого цикла

Код в вопросе:

func (l *Loader) StartAsynchronous() []LoaderProcess { 
    for _, currentProcess := range l.processes { 
     cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...) 
     log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess) 
     go func() { 
      output, err := cmd.CombinedOutput() 
      if err != nil { 
       log.LogMessage("LoaderProcess exited with error status: %+v\n %v", currentProcess, err.Error()) 
      } else { 
       log.LogMessage("LoaderProcess exited successfully: %+v", currentProcess) 
       currentProcess.Log.LogMessage(string(output)) 
      } 
      time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS) 
     }() 
    } 
    return l.processes 
} 

предложил мой фикс:

func (l *Loader) StartAsynchronous() []LoaderProcess { 
    for _, currentProcess := range l.processes { 
     cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...) 
     log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess) 
     localProcess := currentProcess 
     go func() { 
      output, err := cmd.CombinedOutput() 
      if err != nil { 
       log.LogMessage("LoaderProcess exited with error status: %+v\n %v", localProcess, err.Error()) 
      } else { 
       log.LogMessage("LoaderProcess exited successfully: %+v", localProcess) 
       localProcess.Log.LogMessage(string(output)) 
      } 
      time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS) 
     }() 
    } 
    return l.processes 
} 

Но делает действительно решить эту проблему? Я только что переместил ссылку из переменной диапазона в другую локальную переменную, значение которой основано на итерации для каждого цикла, в котором я находится.

ответ

5

Не плохо себя чувствовать, что это общая ошибка для новичков в Go, и да вар currentProcess изменений для каждого цикла, так что ваши goroutines будут использовать последний процесс в срезе l.processes, все вам необходимо передать переменную в качестве параметра анонимной функции, например:

func (l *Loader) StartAsynchronous() []LoaderProcess { 

    for ix := range l.processes { 

     go func(currentProcess *LoaderProcess) { 

      cmd := exec.Command(currentProcess.Command, currentProcess.Arguments...) 
      log.LogMessage("Asynchronously executing LoaderProcess: %+v", currentProcess) 

      output, err := cmd.CombinedOutput() 
      if err != nil { 
       log.LogMessage("LoaderProcess exited with error status: %+v\n %v", currentProcess, err.Error()) 
      } else { 
       log.LogMessage("LoaderProcess exited successfully: %+v", currentProcess) 
       currentProcess.Log.LogMessage(string(output)) 
      } 

      time.Sleep(time.Second * TIME_BETWEEN_SUCCESSIVE_ITERATIONS) 

     }(&l.processes[ix]) // passing the current process using index 

    } 

    return l.processes 
} 
+2

Спасибо за обновленный код, который выглядит великолепно! У меня была грубая ошибка в моем коде, которая заняла более часа, чтобы исправить что-то очень похожее. Я возвращал [] * LoaderProcess, прежде чем не понял, что срез уже является указателем, поэтому я по существу возвращал кусочек указателей, где каждый указатель указывал на тот же экземпляр LoaderProcess, который оказался последней командой для завершения. Каждый раз каждый раз после выполнения. Итак, два больших урока извлечены из одного фрагмента кода. Спасибо. – anon58192932

1

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

Перед исправлением существует только одна переменная , и все горуты ссылались на нее. Это означает, что они не видели значения с момента их запуска, кроме текущего значения. В большинстве случаев это последний из диапазона.

+0

Удивительное спасибо. Можете ли вы подтвердить, что func literal - это просто функция, определенная в строке? Такие, как это требуется в рутинном режиме? – anon58192932

Смежные вопросы