Golang代码运行速度比PHP

时间:2016-09-11 14:41:40

标签: database go performance-testing

Golang的新手,昨天我开始使用Golang并编写了一些实际用PHP编写的代码,我只是希望看到性能上的差异。我在PHP响应中做的完全相同的事情在http请求中是完全相同的,但Golang在编译后表现得非常慢。我试图了解我在Golang中使用的东西我不应该使用,我如何在这段代码中改进性能。我知道迭代地图很慢但PHP使用哈希映射来实现多维数组。我可以保证我使用的SQL查询是完全相同的从PHP粘贴的复制,机器是相同的,并且两个代码中的循环编号相同。

package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "reflect"
    "strings"
)

func main() {
    db, err := sql.Open("mysql", "***:****@tcp(****:3306)/****")
    fmt.Println(reflect.TypeOf(db))
    checkErr(err)
    fmt.Println("Handle Request setup... OK")
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {

        jsonData, err := getListings(db)
        checkErr(err)

        w.Write([]byte(jsonData))

    })
    fmt.Println("Starting Server....")
    fmt.Println("Listening on port 8081")
    http.ListenAndServe(":8081", nil)

}

func getListings(db *sql.DB) ([]byte, error) {
    var userId string = "142"

    normalListings := sqlToArray(db, `******`)

    manualListings := sqlToArray(db, "******")

    var groupIds []string
    for key := range manualListings {

        groupId := "142," + manualListings[key]["group_id"]
        if !stringInSlice(groupId, groupIds) {
            groupIds = append(groupIds, groupId)
        }
    }

    var groupIdsString string
    groupIdsString = strings.Join(groupIds, ", ")

    manualGroups := sqlToArray(db, "*****")

    for key := range manualListings {

        for key2 := range manualGroups {
            groupId := "142," + manualListings[key]["group_id"]

            if groupId == manualGroups[key]["ticket_id"] {
                entry := make(map[string]string)
                entry["ticket_id"] = manualListings[key]["listing_id"]
                entry["date_created"] = manualGroups[key2]["date_created"]
                normalListings = append(normalListings, entry)

            }
        }
    }

    return json.Marshal(normalListings)

}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func sqlToArray(db *sql.DB, sqlString string) []map[string]string {

    rows, err := db.Query(sqlString)
    checkErr(err)
    columns, err := rows.Columns()
    count := len(columns)
    values := make([]interface{}, count)
    valuePtrs := make([]interface{}, count)
    tableData := make([]map[string]string, 0)

    for rows.Next() {

        for i := 0; i < count; i++ {
            valuePtrs[i] = &values[i]
        }
        rows.Scan(valuePtrs...)
        entry := make(map[string]string)
        for i, col := range columns {

            val := values[i]
            b, ok := val.([]byte)
            if ok {
                entry[col] = string(b)
            } else {
                entry[col] = string(b)
            }

        }
        tableData = append(tableData, entry)

    }

    return tableData

}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

编辑: 更改了代码以使用静态类型的结构而不是使用地图并识别出有问题的代码

新代码:

package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "strings"
)

type listingsType struct {
    TicketId    string
    DateCreated string
}

func main() {
    db, err := sql.Open("mysql", "******")

    checkErr(err)
    fmt.Println("Handle Request setup... OK")
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {

        jsonData, err := getListings(db)
        checkErr(err)

        w.Write([]byte(jsonData))

    })
    fmt.Println("Starting Server....")
    fmt.Println("Listening on port 8081")
    http.ListenAndServe(":8081", nil)

}

func getListings(db *sql.DB) ([]byte, error) {
    var userId string = "142"

    normalListings := sqlToArray(db, `*****`)

    manualListings := sqlToArray(db, "*****")

    var groupIds []string

    for _, elem := range manualListings {
        groupId := "142," + elem.DateCreated
        if !stringInSlice(groupId, groupIds) {
            groupIds = append(groupIds, groupId)
        }

    }

    var groupIdsString string
    groupIdsString = strings.Join(groupIds, ", ")
    fmt.Println(groupIdsString)
    manualGroups := sqlToArray(db, "******")

    for _, manualList := range manualListings {

        for _, manualGroup := range manualGroups {
            groupId := "142," + manualList.DateCreated

            if groupId == manualGroup.TicketId {
                var entry listingsType
                entry.TicketId = manualList.TicketId
                entry.DateCreated = manualGroup.DateCreated
                normalListings = append(normalListings, entry)

            }
        }
    }

    return json.Marshal(normalListings)

}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func sqlToArray(db *sql.DB, sqlString string) []listingsType {

    rows, err := db.Query(sqlString)
    checkErr(err)

    tableData := []listingsType{}

    for rows.Next() {

        var entry listingsType
        rows.Scan(&entry.TicketId, &entry.DateCreated)

        tableData = append(tableData, entry)

    }

    return tableData

}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

有问题的代码 一旦我评论下面的代码块,我的代码执行得很好。知道这个循环有什么问题吗?

for _, manualList := range manualListings {

        for _, manualGroup := range manualGroups {
            groupId := "142," + manualList.DateCreated

            if groupId == manualGroup.TicketId {
                var entry listingsType
                entry.TicketId = manualList.TicketId
                entry.DateCreated = manualGroup.DateCreated
                normalListings = append(normalListings, entry)

            }
        }
    }

分析结果

enter image description here

2 个答案:

答案 0 :(得分:0)

好的,顺便解决这个问题。我将请求时间从 5k + MS 带到 500 MS ,现在最终我的PHP代码更慢, 900 MS

我通过实现一个单独的函数去除内部循环搜索,以便在映射的键值中以不同的数据结构获取SQL数据而不是搜索整个数组我创建了值作为我在数组中寻找的键,这样我摆脱了第二个循环,它通过线性搜索字符串来制造麻烦。

manualGroups := sqlToArraySpecial(db, "****")

    for _, manualList := range manualListings {
        //index := stringInSliceArray(manualList.DateCreated, manualGroups)
        groupId := "142," + manualList.DateCreated
        var entry listingsType
        entry.TicketId = manualList.TicketId
        entry.DateCreated = manualGroups[groupId]
        normalListings = append(normalListings, entry)

    }

这是我的新SQL函数

func sqlToArraySpecial(db *sql.DB, sqlString string) map[string]string {

    rows, err := db.Query(sqlString)
    checkErr(err)

    tableData := make(map[string]string)

    for rows.Next() {

        var date_created string
        var ticket_id string

        rows.Scan(&ticket_id, &date_created)
        //fmt.Println(ticket_id)
        tableData[ticket_id] = date_created

    }

    return tableData

}

答案 1 :(得分:0)

虽然这是一个死寂的帖子,但我不禁要注意,因为没有其他人(明确地),而且它有点像#B;重要的是要知道为什么

  • 嵌套for循环显示二次运行时复杂度,
  • 正如您所说,搜索数组需要线性时间,

如此简单地说:

  • 计算时间将增加元素总数的平方。

现在回答为什么这不是php中的情况 - 好吧因为你使用了哈希映射:

    可以说
  • 表现出恒定的时间复杂度

再次,简单地说这意味着:

  • 查找时间与元素数量(也就是集合的大小)无关。

请参阅:big-o

说了这么多,请注意:

  • 我不懂php,
    • 因此不知道有关语言如何实现数组的详细信息,
  • 我不是算法专家,

所以请将我的帖子视为一般案例的陈述。

<强> PCE