最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go切片導(dǎo)致rand.Shuffle產(chǎn)生重復(fù)數(shù)據(jù)的原因與解決方案

 更新時(shí)間:2025年02月17日 09:09:40   作者:飛川001  
在 Go 語(yǔ)言的實(shí)際開(kāi)發(fā)中,切片(slice)是一種非常靈活的數(shù)據(jù)結(jié)構(gòu),然而,由于其底層數(shù)據(jù)共享的特性,在某些情況下可能會(huì)導(dǎo)致意想不到的 Bug,本文將詳細(xì)分析 rand.Shuffle 之后,切片中的數(shù)據(jù)出現(xiàn)重復(fù)的問(wèn)題,探討其根本原因,并給出最佳解決方案,需要的朋友可以參考下

問(wèn)題描述

在一個(gè) Go 服務(wù)端 API 里,我們需要按照 curBatch 參數(shù)進(jìn)行分頁(yè),從 interestCfg 里分批選取 interestTagNum 個(gè)興趣標(biāo)簽,并在返回結(jié)果前對(duì)選中的數(shù)據(jù)進(jìn)行隨機(jī)打亂。

全部興趣標(biāo)簽示例:

{
    "InterestTags": [
        {"interestName":"Daily Sharing"},
        {"interestName":"Gaming"},
        {"interestName":"AI"},
        {"interestName":"test"},
        {"interestName":"Sports"},
        {"interestName":"Cars"},
        {"interestName":"other"}
    ]
}

現(xiàn)象回顧

當(dāng) curBatch = 0 時(shí),返回的數(shù)據(jù)是正確的:

{
    "InterestTags": [
        { "interestName": "Daily Sharing" },
        { "interestName": "Gaming" },
        { "interestName": "AI" }
    ]
}

但當(dāng) curBatch = 2 時(shí),測(cè)試環(huán)境出現(xiàn)了數(shù)據(jù)重復(fù)的問(wèn)題:(本地運(yùn)行正常)

1. 不隨機(jī)時(shí)(正確的結(jié)果):

{
    "InterestTags": [
        { "interestName": "other" },
        { "interestName": "Daily Sharing" },
        { "interestName": "Gaming" }
    ]
}

2. 隨機(jī)后(錯(cuò)誤的結(jié)果):

{
    "InterestTags": [
        { "interestName": "Gaming" },
        { "interestName": "Gaming" },
        { "interestName": "AI" }
    ]
}

問(wèn)題:

  • “Gaming” 出現(xiàn)了兩次,而 “test” 消失了!
  • 本地環(huán)境正常,但測(cè)試環(huán)境異常,導(dǎo)致調(diào)試變得困難。

問(wèn)題排查

數(shù)據(jù)的選擇和隨機(jī)操作邏輯如下:

interestTags := make([]model.InterestConfig, 0, interestConfig.InterestTagNum)

// 處理interestConfig,根據(jù)curBatch分批次處理
if len(interestConfig.InterestCfg) > 0 && interestConfig.InterestTagNum > 0 {
    interestAllTags := interestConfig.InterestCfg
    numBatches := (len(interestAllTags) + int(interestConfig.InterestTagNum) - 1) / int(interestConfig.InterestTagNum)
    startIdx := (curBatch % numBatches) * int(interestConfig.InterestTagNum)
    endIdx := startIdx + int(interestConfig.InterestTagNum)

    if endIdx > len(interestAllTags) {
        interestTags = interestAllTags[startIdx:]
        interestTags = append(interestTags, interestAllTags[:(endIdx-len(interestAllTags))]...)
    } else {
        interestTags = interestAllTags[startIdx:endIdx]
    }
}

// 隨機(jī)打亂 interestTags 順序
r := rand.New(rand.NewSource(time.Now().UnixNano()))
r.Shuffle(len(interestTags), func(i, j int) {
    interestTags[i], interestTags[j] = interestTags[j], interestTags[i]
})

關(guān)鍵點(diǎn)分析

  1. interestTags = interestAllTags[startIdx:endIdx] 直接從 interestAllTags 取出數(shù)據(jù),但切片是引用類型,因此 interestTags 共享了 interestAllTags 的底層數(shù)組。
  2. rand.Shuffle 隨機(jī)交換 interestTags 里的元素,但 interestTags 指向 interestAllTags,可能導(dǎo)致原始數(shù)據(jù)被錯(cuò)誤修改
  3. 本地和測(cè)試環(huán)境不一致,可能與 Go 運(yùn)行時(shí)的內(nèi)存管理機(jī)制高并發(fā)場(chǎng)景下的切片擴(kuò)容行為有關(guān)。

代碼驗(yàn)證

為了驗(yàn)證 interestTags 是否共享 interestAllTags 的底層數(shù)組,我們打印切片元素的內(nèi)存地址:

fmt.Println("Before Shuffle:")
for i, tag := range interestTags {
    fmt.Printf("[%d] %p: %s\n", i, &interestTags[i], tag.InterestName)
}

r.Shuffle(len(interestTags), func(i, j int) {
    interestTags[i], interestTags[j] = interestTags[j], interestTags[i]
})

fmt.Println("After Shuffle:")
for i, tag := range interestTags {
    fmt.Printf("[%d] %p: %s\n", i, &interestTags[i], tag.InterestName)
}

解決方案

方案 1:使用 append 進(jìn)行數(shù)據(jù)拷貝

為了避免 interestTags 共享 interestAllTags 的底層數(shù)組,我們需要顯式拷貝數(shù)據(jù):

interestTags = make([]model.InterestConfig, 0, interestConfig.InterestTagNum)
if endIdx > len(interestAllTags) {
    interestTags = append(interestTags, interestAllTags[startIdx:]...)
    interestTags = append(interestTags, interestAllTags[:(endIdx-len(interestAllTags))]...)
} else {
    interestTags = append(interestTags, interestAllTags[startIdx:endIdx]...)
}

為什么這樣做?

  • append(..., interestAllTags[startIdx:endIdx]...) 創(chuàng)建新的切片,避免 interestTags 共享 interestAllTags 的底層數(shù)據(jù)。
  • 獨(dú)立的數(shù)據(jù)拷貝 確保 rand.Shuffle 只影響 interestTags,不會(huì)破壞原始 interestAllTags

總結(jié)

1. 問(wèn)題原因

  • Go 切片是引用類型,直接賦值 interestTags = interestAllTags[startIdx:endIdx] 不會(huì)創(chuàng)建新數(shù)據(jù),而是共享底層數(shù)組
  • rand.Shuffle 可能影響 interestAllTags,導(dǎo)致元素重復(fù)。
  • 本地環(huán)境正常,但測(cè)試環(huán)境異常,可能與 Go 內(nèi)存管理切片擴(kuò)容策略有關(guān)。

2. 解決方案

  • 使用 append 進(jìn)行數(shù)據(jù)拷貝,確保 interestTags 是獨(dú)立的數(shù)據(jù),避免 rand.Shuffle 影響原始 interestAllTags

經(jīng)驗(yàn)總結(jié)

  1. Go 切片是引用類型,不能直接賦值,否則可能共享底層數(shù)據(jù)。
  2. 使用 rand.Shuffle 之前,必須確保數(shù)據(jù)是獨(dú)立的副本。
  3. 盡量使用 append 創(chuàng)建新的切片,避免底層數(shù)組共享問(wèn)題。
  4. 不同環(huán)境表現(xiàn)不一致時(shí),應(yīng)檢查內(nèi)存管理、并發(fā)情況及數(shù)據(jù)結(jié)構(gòu)副作用。

以上就是Go切片導(dǎo)致rand.Shuffle產(chǎn)生重復(fù)數(shù)據(jù)的原因與解決方案的詳細(xì)內(nèi)容,更多關(guān)于Go rand.Shuffle產(chǎn)生重復(fù)數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言學(xué)習(xí)教程之指針的示例詳解

    Go語(yǔ)言學(xué)習(xí)教程之指針的示例詳解

    這篇文章主要通過(guò)簡(jiǎn)單的練習(xí)來(lái)讓大家對(duì)Go語(yǔ)言中的指針有所了解,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定幫助,需要的可以參考一下
    2022-09-09
  • Go語(yǔ)言對(duì)接微信支付與退款指南(示例詳解)

    Go語(yǔ)言對(duì)接微信支付與退款指南(示例詳解)

    在互聯(lián)網(wǎng)技術(shù)日益發(fā)展的背景下,Go語(yǔ)言憑借并發(fā)處理能力,在后端開(kāi)發(fā)中大放異彩,本文詳細(xì)介紹如何使用Go語(yǔ)言對(duì)接微信支付,完成支付和退款功能,包括準(zhǔn)備工作、初始化微信支付客戶端、實(shí)現(xiàn)支付功能,以及處理支付回調(diào)和退款等
    2024-10-10
  • Golang中的select語(yǔ)句及其應(yīng)用實(shí)例

    Golang中的select語(yǔ)句及其應(yīng)用實(shí)例

    本文將介紹Golang中的select語(yǔ)句的使用方法和作用,并通過(guò)代碼示例展示其在并發(fā)編程中的實(shí)際應(yīng)用,此外,還提供了一些與select相關(guān)的面試題,幫助讀者更好地理解和應(yīng)用select語(yǔ)句
    2023-12-12
  • GO實(shí)現(xiàn)文件上傳操作

    GO實(shí)現(xiàn)文件上傳操作

    這篇文章主要為大家詳細(xì)介紹了GO實(shí)現(xiàn)文件上傳操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Golang?rabbitMQ生產(chǎn)者消費(fèi)者實(shí)現(xiàn)示例

    Golang?rabbitMQ生產(chǎn)者消費(fèi)者實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了Golang?rabbitMQ生產(chǎn)者消費(fèi)者實(shí)現(xiàn)的示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • 基于golang中container/list包的用法說(shuō)明

    基于golang中container/list包的用法說(shuō)明

    這篇文章主要介紹了基于golang中container/list包的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Go語(yǔ)言bufio庫(kù)的全面指南與實(shí)戰(zhàn)技巧詳解

    Go語(yǔ)言bufio庫(kù)的全面指南與實(shí)戰(zhàn)技巧詳解

    這篇文章主要為大家全面介紹一下?bufio?庫(kù)的核心組件與功能,包括?Reader、Writer?和?Scanner?等并深入探討它們?cè)趯?shí)際編程中的運(yùn)用場(chǎng)景和技巧,感興趣的可以了解下
    2024-01-01
  • Go語(yǔ)言中json序列化優(yōu)化技巧

    Go語(yǔ)言中json序列化優(yōu)化技巧

    在Go語(yǔ)言開(kāi)發(fā)中,JSON因其簡(jiǎn)潔和廣泛的兼容性,通常被用作數(shù)據(jù)交換的主要序列化格式,本文將探討JSON希望對(duì)大家有所幫助序列化的一些局限性,也算是一個(gè)小坑吧,并給出一些常用的解決方案,
    2024-11-11
  • 從errors到pkg-errors詳解Go語(yǔ)言中的錯(cuò)誤處理指南

    從errors到pkg-errors詳解Go語(yǔ)言中的錯(cuò)誤處理指南

    錯(cuò)誤處理是編程語(yǔ)言中的重要組成部分,它直接影響程序的可靠性和可維護(hù)性,本文將深入探討Go語(yǔ)言中的錯(cuò)誤處理,從標(biāo)準(zhǔn)庫(kù)的errors包到第三方的pkg-errors庫(kù),幫助開(kāi)發(fā)者掌握錯(cuò)誤處理的最佳實(shí)踐,提高代碼的質(zhì)量和可維護(hù)性
    2026-04-04
  • go循環(huán)依賴的最佳解決方案

    go循環(huán)依賴的最佳解決方案

    ? import cycle not allowed(循環(huán)依賴不被允許)相信作為每一個(gè)golang語(yǔ)言使用研發(fā),都遇到過(guò)這個(gè)令人頭痛的報(bào)錯(cuò),循環(huán)依賴是指兩個(gè)或多個(gè)模塊之間互相依賴,形成了一個(gè)閉環(huán)的情況,本文會(huì)結(jié)合部分案例對(duì)解決方案進(jìn)行講解,需要的朋友可以參考下
    2023-10-10

最新評(píng)論

龙口市| 荆州市| 赤壁市| 美姑县| 祁阳县| 岱山县| 东莞市| 红桥区| 类乌齐县| 大田县| 璧山县| 岫岩| 太仓市| 太和县| 洪雅县| 宜都市| 保山市| 三亚市| 长武县| 晋江市| 九江市| 额敏县| 宁南县| 虎林市| 化德县| 华阴市| 鱼台县| 陈巴尔虎旗| 自治县| 南召县| 兴和县| 滨州市| 隆子县| 黎城县| 宝清县| 德江县| 车险| 永寿县| 竹北市| 双辽市| 永修县|