2016-01-15 5 views
0

У моей программы многолетняя задача. У меня есть список jdIdList, который слишком большой - до 1000000 элементов, поэтому код ниже не работает. Есть ли способ улучшить код с лучшим использованием goroutines?Разумное использование goroutines в программах Go

Кажется, у меня слишком много запущенных goroutines, из-за чего мой код не запускается.

Что такое разумное количество горутинцев для бега?

var wg sync.WaitGroup 
wg.Add(len(jdIdList)) 
c := make(chan string) 

// just think jdIdList as [0...1000000] 
for _, jdId := range jdIdList { 
    go func(jdId string) { 
     defer wg.Done() 
     for _, itemId := range itemIdList { 
      // following code is doing some computation which consumes much time(you can just replace them with time.Sleep(time.Second * 1) 
      cvVec, ok := cvVecMap[itemId] 
      if !ok { 
       continue 
      } 
      jdVec, ok := jdVecMap[jdId] 
      if !ok { 
       continue 
      } 
      // long time compute 
      _ = 0.3*computeDist(jdVec.JdPosVec, cvVec.CvPosVec) + 0.7*computeDist(jdVec.JdDescVec, cvVec.CvDescVec) 
     } 
     c <- fmt.Sprintf("done %s", jdId) 
    }(jdId) 

} 

go func() { 
    for resp := range c { 
     fmt.Println(resp) 
    } 
}() 
+1

В чем вопрос? –

+0

@FilipHaglund Я меняю вопрос – roger

+0

Мне все еще трудно понять, что вы на самом деле пытаетесь спросить. Вы говорите, что ваша проблема в том, что 'jdIdList' слишком большой, но это не ваша фактическая проблема, не так ли? Что происходит, и что вы хотите? –

ответ

2

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

Вот версия вашего кода, в которой используется ограниченное число рабочих горопичей вместо миллиона goroutines, как в вашем примере. Так как только несколько goroutines запускаются сразу, они имеют намного больше памяти, доступной каждому, прежде чем система начнет своп. Удостоверьтесь, что для каждого небольшого вычисления памяти требуется, чтобы количество параллельных goroutines было меньше, чем у вашей памяти, поэтому если код внутри цикла for jdId := range work требует менее 1 ГБ памяти, и у вас есть 4 ядра и не менее 4 ГБ ОЗУ , установка clvl до 4 должна работать нормально.

Я также удалил группы waitgroups. Код по-прежнему корректен, но использует только каналы для синхронизации. A для диапазона диапазона по каналу считывает с этого канала до тех пор, пока он не будет закрыт. Так мы говорим рабочим потокам, когда мы закончили.

https://play.golang.org/p/Sy3i77TJjA

runtime.GOMAXPROCS(runtime.NumCPU()) // not needed on go 1.5 or later 
c := make(chan string) 
work := make(chan int, 1) // increasing 1 to a higher number will probably increase performance 
clvl := 4 // runtime.NumCPU() // simulating having 4 cores, use NumCPU otherwise 
var wg sync.WaitGroup 
wg.Add(clvl) 
for i := 0; i < clvl; i++ { 
    go func(i int) { 
     for jdId := range work { 
      time.Sleep(time.Millisecond * 100) 
      c <- fmt.Sprintf("done %d", jdId) 
     } 
     wg.Done() 
    }(i) 
} 

// give workers something to do 
go func() { 
    for i := 0; i < 10; i++ { 
     work <- i 
    } 

    close(work) 
}() 

// close output channel when all workers are done 
go func() { 
    wg.Wait() 
    close(c) 
}() 

count := 0 
for resp := range c { 
    fmt.Println(resp, count) 
    count += 1 
} 

, который генерируется этот вывод на ходе игровой площадки, при моделировании четыре ядра процессора.

done 1 0 
done 0 1 
done 3 2 
done 2 3 
done 5 4 
done 4 5 
done 7 6 
done 6 7 
done 9 8 
done 8 9 

Обратите внимание, что заказ не гарантируется. Переменная jdId содержит требуемое значение. Вы всегда должны проверять свои параллельные программы, используя go race detector.

Также обратите внимание, что если вы используете go 1.4 или ранее и не задали переменную окружения GOMAXPROCS для количества ядер, вы должны сделать это или добавить runtime.GOMAXPROCS(runtime.NumCPU()) в начало вашей программы.

+0

У меня есть мертвый замок с кодом, что не так? – roger

+0

вы можете попробовать это, ваш код сделает 'dead lock', http://play.golang.org/p/1CjQrnyQzQ – roger

+0

Я пропустил этот тупик. Это хорошо, потому что это означает, что вычисление действительно закончено; выход, который вы получили, - это весь выход. Если мы добавим группу waitgroup с элементами 'clvl', удаляем каждый раз, когда рабочий выходит из финального цикла печати, когда эта группа wait завершена, мы не будем заходить в тупик. –

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