Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 使用goroutines丢失数据_Sql Server_Go_Aws Lambda_Goroutine - Fatal编程技术网

Sql server 使用goroutines丢失数据

Sql server 使用goroutines丢失数据,sql-server,go,aws-lambda,goroutine,Sql Server,Go,Aws Lambda,Goroutine,我正在编写一个AWS lambda代码来查询RDS表,将其转换为JSON并返回它。但是我在JSON中看到的所有记录都不是SQL查询返回的记录。假设我从表中查询1500条记录,但每次JSON中只有1496到1500条记录(少0-5条记录)。我怀疑我把sync.WaitGroup搞砸了 下面是SQL Server查询 SELECT TOP 1500 * FROM IMBookingApp.dbo.BA_Contact__c WHERE ContactId > 0 下面是我的代码 // Con

我正在编写一个AWS lambda代码来查询RDS表,将其转换为JSON并返回它。但是我在JSON中看到的所有记录都不是SQL查询返回的记录。假设我从表中查询1500条记录,但每次JSON中只有1496到1500条记录(少0-5条记录)。我怀疑我把
sync.WaitGroup
搞砸了

下面是SQL Server查询

SELECT TOP 1500 * FROM IMBookingApp.dbo.BA_Contact__c
WHERE ContactId > 0
下面是我的代码

// Convert the rows object to slice of objects for every row
func parseRow(rows *sql.Rows, totalColumns int) []string {

    receiver := make([]string, totalColumns)

    is := make([]interface{}, len(receiver))
    for i := range is {
        is[i] = &receiver[i]
    }

    err := rows.Scan(is...)

    if err != nil {
        fmt.Println("Error reading rows: " + err.Error())
    }

    TotalRecordsInParseRowfunction++
    return receiver
}

// Query the given table and return JSON response
func queryTable(conn *sql.DB, query string) (string, error) {

    // Query Table
    rows, err := conn.Query(query)
    if err != nil {
        fmt.Println("DATABASE ERROR:", err)
        return "", errors.New("DATABASE ERROR:" + err.Error())
    }

    println("Rows:", rows)
    defer rows.Close()

    // Get the column names
    columns, err := rows.Columns()
    // fmt.Println("columns", columns)
    if err != nil {
        fmt.Println("DATABASE ERROR:", err)
        return "", errors.New("DATABASE ERROR:" + err.Error())
    }

    totalColumns := len(columns)
    var resp []map[string]string // Declare the type of final response which will be used to create JSON
    var waitgroup sync.WaitGroup

    // Iterate over all the rows returned
    for rows.Next() {

        waitgroup.Add(1)
        TotalRecordsCount++
        row := parseRow(rows, totalColumns)

        go func() {
            // Create a map of the row
            respRow := map[string]string{} // Declare the type of each row of response
            for count := range row {
                respRow[columns[count]] = row[count]
            }
            // fmt.Println("\n\nrespRow", respRow)

            resp = append(resp, respRow)
            TotalRecordsAppendedCount++
            waitgroup.Done()
        }()
    }
    waitgroup.Wait()

    // If no rows are returned
    if len(resp) == 0 {
        fmt.Println("MESSAGE: No records are available")
        return "", errors.New("MESSAGE: No records are available")
    }

    // Create JSON
    respJSON, _ := json.Marshal(resp)
    fmt.Println("Response", string(respJSON))

    fmt.Println("\n--------------Summary---------------")
    fmt.Println("TotalRecordsInParseRowfunction", TotalRecordsInParseRowfunction)
    fmt.Println("TotalRecordsCount", TotalRecordsCount)
    fmt.Println("TotalRecordsAppendedCount", TotalRecordsAppendedCount)
    fmt.Println("Object Length", len(resp))

    return string(respJSON), nil // Return JSON

}
下面是我得到的输出摘要

--------------Summary---------------
TotalRecordsInParseRowfunction 1500
TotalRecordsCount 1500
TotalRecordsAppendedCount 1500
Object Length 1496

你的代码很活泼。多个goroutine正在写入
resp
,没有任何互斥,因此会丢失数据

您可以在其周围添加互斥锁解锁。但是,goroutine中的代码并不保证它自己的goroutine,因为它是一个简单的映射添加。在goroutine中处理这些代码会容易得多,并且可能在没有goroutine调度开销的情况下运行得更快。除非你打算在这个goroutine中有更多的逻辑,否则我建议你删除它

下面是关于可能发生的事情的更多信息:首先,在当前版本的go中,goroutine只有在调用某些库函数时才会向其他goroutine屈服。看看代码,您的goroutines不太可能会让步。因为您已经观察到数据丢失(这意味着存在竞争条件),所以您可能有多个内核

比赛在这里进行:

resp = append(resp, respRow)
在没有互斥的情况下,一个goroutine可以查看
resp
,看到它可以写入其
n
th元素。另一个goroutine(在单独的核心上运行)也可以做同样的事情,并在那里成功地写入。但是第一个goroutine仍然认为元素是空的,所以覆盖它,并更新
resp
。发生这种情况时,将丢失一个元素


如果您在这段代码中添加互斥,您将强制所有goroutine按顺序运行,因为它们实际上没有做任何其他事情。此外,由于goroutine的执行顺序是随机的,因此最终将得到随机排序的
resp
。简而言之,这是您应该顺序执行代码的实例之一。

当您添加一个互斥锁(在
queryTable
中的
for
循环之前声明)时会发生什么情况,该互斥锁在
resp=append(resp,respRow)
之前锁定,然后在它之后解锁?可能有些项目在那里丢失了我以前没有使用过互斥锁。让我试试。谢谢你的回答。我已经在代码中添加了互斥,但仍有一些行丢失。您可以在这里看到我的更改-您正在为每一行创建一个单独的互斥,因此您并没有真正阻止竞争。将互斥声明移到for循环之外。是。您在goroutine中所做的工作量非常小,并且您拥有一个共享资源。如果创建3k goroutine,则创建3k*2k堆栈空间,并且所有goroutine都在等待锁定。你可以使用频道,但你所做的工作量仍然很小。测量并查看。“3K行”不是对资源本身的估计。为了使3K行中每个行的多个包的并发处理具有意义,独立于所有其他包处理此类包所花费的CPU周期量必须相当大;否则就不会有性能提升,也可能会有净性能损失。这可能不是直接花费CPU时间(比如对这些行中的数据进行运算),而是像查询外部数据源等。关键是这些活动本身必须是可并行的。