我在Go中实现了一些排序算法,现在我想在随机整数上测试它们的性能。所以我写了以下程序。我按照类似的格式:https://gobyexample.com/timeouts
但是,似乎超时没有正常启动。以下是我的代码:
package main
import (
"allanpinkerton.com/algorithms/sorting"
"fmt"
"math/rand"
"os"
"strconv"
"time"
)
// Prints out the time elapsed since start
func timeExecution(startTime time.Time, functionName string, inputSize int) string {
executionTime := time.Since(startTime)
return fmt.Sprintf("%-20s took %10.4fms to sort %d elements\n", functionName, float64(executionTime.Nanoseconds())/1000000, inputSize)
}
// Generates file with n random ints named integerArray + n
func generateRandomIntegers(n int, filename string) {
arr := make([]int, n)
for i := 0; i < n; i++ {
arr[i] = rand.Int()
}
f, _ := os.Create(filename)
defer f.Close()
for _, num := range arr {
f.WriteString(strconv.Itoa(num) + " ")
}
f.WriteString("\n")
f.Sync()
fmt.Printf("Generated " + filename + " with " + strconv.Itoa(n) + " elements.\n")
}
func checkError(err error) {
if err != nil {
panic(err)
}
}
func main() {
sortingFunctions := map[string]interface{}{
"InsertionSort": sorting.InsertionSort,
"QuickSortLastElement": sorting.QuickSortLastElement,
"QuickSortRandom": sorting.QuickSortRandom,
}
if len(os.Args) != 2 {
fmt.Printf("No size specified.\n")
return
}
size := os.Args[1]
sizeInt, err := strconv.Atoi(size)
checkError(err)
arr := make([]int, sizeInt)
for i := 0; i < sizeInt; i++ {
arr[i] = rand.Int()
}
fmt.Println("Generated " + size + " integers.")
mainChannel := make(chan string)
for k, v := range sortingFunctions {
newArr := make([]int, len(arr))
copy(newArr, arr)
go func(name string, v interface{}) {
start := time.Now()
v.(func([]int))(newArr)
result := timeExecution(start, name, len(newArr))
mainChannel <- result
}(k, v)
}
for _ = range sortingFunctions {
select {
case result := <-mainChannel:
fmt.Printf(result)
case <-time.After(time.Second):
fmt.Println("Timeout")
}
}
return
}
顶部只是一堆助手,但主要功能还有一些有趣的事情。我跑了go install
并对抗了150,000个元素,得到了以下答案:
Generated 150000 integers.
QuickSortLastElement took 15.0037ms to sort 150000 elements
InsertionSort took 7599.5884ms to sort 150000 elements
QuickSortRandom took 15.1697ms to sort 150000 elements
显然,插入排序超过7秒,但超时应在1秒后触发。超时是否有任何理由不发射?
所以我尝试通过将sortingFuncs map更改为:
,从sort包中切换出sort.Ints函数的自定义排序程序。sortingFunctions := map[string]func([]int){
"InsertionSort": sort.Ints,
"QuickSortLastElement": sort.Ints,
"QuickSortRandom": sort.Ints,
}
问题解决了。所以这是我的自定义排序函数,可防止超时被触发。我是否需要添加一些功能才能使它们并行运行?
这是一个连接版本,包含操场上的所有代码。 https://play.golang.org/p/SBgDTGyUyp
答案 0 :(得分:0)
由于您在最终循环中使用time.After(time.Second)
,因此每次结果到达时都会重置超时。相反,尝试
timeoutChannel := time.After(time.Second)
for _ = range sortingFunctions {
select {
case result := <-mainChannel:
fmt.Printf(result)
case <-timeoutChannel:
fmt.Println("Timeout")
}
}
上面的代码现在可以正确捕获超时。它仍然没有按预期工作,因为循环的内容总是执行三次(因为sortingFunctions
有三个元素),并且任何超时都计入这三次迭代。使用来自go playground的代码我现在得到以下输出:
Generated 90000 integers.
QuickSortRandom took 9.4268ms to sort 90000 elements
Timeout
QuickSortLastElement took 8.6096ms to sort 90000 elements
答案 1 :(得分:0)
您在Go操场上发布的代码提供了以下输出:
Generated 90000 integers.
InsertionSort took 4465.6230ms to sort 90000 elements
QuickSortLastElement took 11.2758ms to sort 90000 elements
QuickSortRandom took 11.6547ms to sort 90000 elements
我怀疑您没有看到调用超时的事实是由于InsertionSort
确实进行了任何函数调用,因此does not allow调度程序在goroutine之间切换。由于Go默认只使用一个线程,因此其他所有内容都要等到InsertionSort
完成。
为了测试这个假设,我尝试用GOMAXPROCS = 4调用程序(允许Go调度程序使用4个操作系统线程):在这种情况下,我得到输出
Generated 90000 integers.
QuickSortRandom took 21.1900ms to sort 90000 elements
QuickSortLastElement took 11.4538ms to sort 90000 elements
Timeout
正如所料。 (奇怪的是,对于GOMAXPROCS = 2,行为不是确定性的,有时超时触发,有时则没有。我没有试图找出为什么2个线程在这里并不总是足够。)