2013-12-11 2 views
1

Я написал этот грубый минимальный код кучи, который является переводом аналогичной программы, написанной на C++. Я думаю, что я должен использовать фрагменты неправильно, потому что код go работает медленнее, чем код на C++. Вставка и удаление 100 000 целых чисел занимает около 19 секунд в Go, но только 1,73 секунды на C++. Может ли кто-нибудь предложить какой-нибудь совет? Или Go намного медленнее, чем C++? Я использую такой код под Linux: «время ./pqgo -n 100000 -d 100000>/dev/null». Вот код:Является ли моя тестовая программа с приоритетной очередью очень медленной, потому что я не использую правильно?

package main 

import (
     "fmt" 
     "time" 
     "math/rand" 
     "flag" 
) 

func insert(key int, lPq []int) []int { 
    lPq = append(lPq[:], key) 
    i := len(lPq) - 1 

    for ; i > 1 && lPq[ i/2 ] > lPq[i] ; { 
     lTemp := lPq[ i/2 ] 
     lPq[ i/2 ] = lPq[i] 
     lPq[i] = lTemp 
     i = i/2 
    } 
    return lPq 
} 

func delete_min(lPq []int) (int, []int) { 
    lRetVal := lPq[1] 

    lPq[1] = lPq[ len(lPq)-1 ] 
    lPq = lPq[0:len(lPq)-1 ] 

    k := 1 
    for ; 2*k <= len(lPq); { 
    j := 2*k 
    if k < len(lPq) && lPq[j] > lPq[j+1] { 
     j++ 
    } 
    if lPq[k] <= lPq[j] { 
    break 
    } 
    lTemp := lPq[k] 
    lPq[k] = lPq[j] 
    lPq[j] = lTemp 
    } 
    return lRetVal, lPq 
} 

func main() { 
    var lPq []int 
    lPq = append(lPq[:], -9999) 

    var ip *int = flag.Int("n", 8, "help message") 
    var ip2 *int = flag.Int("d", 8, "help message2") 
     flag.Parse() 
     lNum := *ip 

     fmt.Printf("lNum= %d\n", lNum) 

    lPq = insert(17, lPq[:]); 
    lPq = insert(19, lPq[:]); 
    lPq = insert(9, lPq[:]); 
    lPq = insert(4 , lPq[:]); 
    lPq = insert (12, lPq[:]); 

     rand.Seed(time.Now().UnixNano()) 
     for i := 0; i < lNum; i++ { 
     lKey := rand.Intn(4*lNum) 
      lPq = insert(lKey, lPq[:])  
    } 
    fmt.Printf("pq.size = %d\n", len(lPq)) 

     lPrintTo := len(lPq) 
    if lPrintTo > 64 { 
      lPrintTo = 64 
     } 
     var num int 
     for _, num = range lPq[0:lPrintTo] { 
     fmt.Printf("%d ", num) 
    } 
    fmt.Println(""); 

    var lMin int 
    for index := 1; index < 3; index++ { 
     lMin, lPq = delete_min(lPq[:]) 
      fmt.Printf("lMin = %d\n", lMin) 
      for _, num = range lPq[0:lPrintTo] { 
     fmt.Printf("%d ", num) 
     } 
     fmt.Println(""); 
    } 

    lPq = insert(3, lPq[:]); 
    lPq = insert(4, lPq[:]); 
    lPq = insert(1, lPq[:]); 
    lPq = insert(8, lPq[:]); 
    lPq = insert(20, lPq[:]); 
    lPq = insert(21, lPq[:]); 
    lPq = insert(6, lPq[:]); 
    lPq = insert (11, lPq[:] ); 

    lNumToDelete := len(lPq) 
    lNumToDelete = *ip2 

    for index := 1; index < lNumToDelete-1; index++ { 
    lMin, lPq = delete_min(lPq[:]) 

     lPrintTo = len(lPq) 
     if lPrintTo > 64 { 
      lPrintTo = 64 
     } 
     fmt.Printf("lPrintTo = %d\n",lPrintTo) 
     fmt.Printf("pq.size = %d\n", len(lPq)) 
     for _, num = range lPq[0:lPrintTo] { 
      fmt.Printf("%d ", num) 
     } 
    fmt.Println(""); 
    } 

} 

// gccgo -Og -I/devserv-home/rspikol/include -o pqgo pq.go -L/devserv-home/rspikol/lib 
+0

полутуши комментарий. Было бы неплохо, если бы вы могли отступать от своего кода в соответствии со стандартом Go. Вам не нужно делать это вручную, инструмент «gofmt» сделает это за вас, или, альтернативно, вы можете использовать кнопку «Формат» на игровой площадке. Это сделало бы ваш код намного легче читать для людей, которые использовали для написания и чтения кода Go. Благодаря! – siritinga

ответ

4

Создает ли ваша версия на C++ одинаковый объем вывода?

Последний цикл запускает lNumToDelete (100 000) раз и печатает до 64 значений из очереди на каждой итерации. Это много выходных данных, и для форматирования и записи требуется время, даже если оно будет /dev/null.

Комментируя вызовы fmt.Printf() внутри цикла удаления, программа запускалась значительно быстрее для меня.

Несколько других предложений:

  • fmt.Printf("a = %d\n", b) можно заменить fmt.Println("a =", b)
  • lPq[:] можно заменить lPq
  • ЗАКАНЧИВАТЬ Go профилирующие инструменты: http://blog.golang.org/profiling-go-programs
+0

Также задайтесь вопросом, является ли скорость rand'а его частью, поскольку я сомневаюсь, что RNG Go оптимизирован. Если профилирование показывает, что вы можете заменить его глупым заглушкой, которая генерирует не-очень-псевдослучайные, но все еще равномерно распределенные числа («r = (r^const1) * (const2 | 1); r^= r> > const3; 'или что-то еще), если вы хотите обойти это. – twotwotwo

+0

Спасибо! Я пропустил fmt.Printf() внутри цикла delete. Да, I/O - это определенно время, даже если оно перенаправлено! – bspikol

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