[{"data":1,"prerenderedAt":2955},["ShallowReactive",2],{"page-\u002Fgo\u002F19-sync-package":3},{"id":4,"title":5,"body":6,"description":2948,"extension":2949,"meta":2950,"navigation":72,"path":2951,"seo":2952,"stem":2953,"__hash__":2954},"content\u002Fgo\u002F19-sync-package.md","19 — sync Package",{"type":7,"value":8,"toc":2941},"minimark",[9,13,22,34,2817,2920,2924,2937],[10,11,5],"h1",{"id":12},"_19-sync-package",[14,15,16,17,21],"p",{},"Channels are for \"communicate by sharing\"; ",[18,19,20],"code",{},"sync"," provides lower-level primitives when you need mutexes, coordination, and object reuse.",[23,24,26,29,30,33],"h2",{"id":25},"syncmutex-and-syncrwmutex-internals",[18,27,28],{},"sync.Mutex"," and ",[18,31,32],{},"sync.RWMutex"," — Internals",[35,36,38,551,558],"code-wrapper",{"language":37},"go",[39,40,44],"pre",{"className":41,"code":42,"language":37,"meta":43,"style":43},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F Mutex is a binary semaphore — only one goroutine in the critical section.\n\u002F\u002F Internally it's an atomic int with a waiter queue (futex-based on Linux).\n\u002F\u002F Go's Mutex is NOT reentrant — locking twice from the same goroutine deadlocks.\n\ntype Counter struct {\n    mu    sync.Mutex\n    count int\n}\n\nfunc (c *Counter) Inc() {\n    c.mu.Lock()\n    defer c.mu.Unlock()  \u002F\u002F ✅ always defer Unlock — runs even on panic\n    c.count++\n}\n\nfunc (c *Counter) Get() int {\n    c.mu.Lock()\n    defer c.mu.Unlock()\n    return c.count\n}\n\n\u002F\u002F ─── RWMutex — multiple readers OR one writer ───\ntype Cache struct {\n    mu    sync.RWMutex\n    data  map[string]string\n}\n\nfunc (c *Cache) Get(key string) (string, bool) {\n    c.mu.RLock()         \u002F\u002F ✅ multiple readers can hold RLock simultaneously\n    defer c.mu.RUnlock()\n    val, ok := c.data[key]\n    return val, ok\n}\n\nfunc (c *Cache) Set(key, val string) {\n    c.mu.Lock()          \u002F\u002F ✅ exclusive — blocks all readers and writers\n    defer c.mu.Unlock()\n    c.data[key] = val\n}\n\n\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n\u002F\u002F │ When to use RWMutex vs Mutex:                                        │\n\u002F\u002F │   RWMutex: reads vastly outnumber writes AND the critical section     │\n\u002F\u002F │            is non-trivial (the RLock overhead is higher than Mutex)  │\n\u002F\u002F │   Mutex:   balanced read\u002Fwrite or short critical sections             │\n\u002F\u002F │   RWMutex overhead: 2 atomic ops per RLock (vs 1 for Lock)            │\n\u002F\u002F │   For write-heavy or short sections, Mutex is faster.                 │\n\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n","",[18,45,46,55,61,67,74,92,106,115,121,126,154,166,184,193,198,203,229,238,249,258,263,268,274,286,298,319,324,329,370,384,396,408,416,421,426,457,470,481,493,498,503,509,515,521,527,533,539,545],{"__ignoreMap":43},[47,48,51],"span",{"class":49,"line":50},"line",1,[47,52,54],{"class":53},"sdCPZ","\u002F\u002F Mutex is a binary semaphore — only one goroutine in the critical section.\n",[47,56,58],{"class":49,"line":57},2,[47,59,60],{"class":53},"\u002F\u002F Internally it's an atomic int with a waiter queue (futex-based on Linux).\n",[47,62,64],{"class":49,"line":63},3,[47,65,66],{"class":53},"\u002F\u002F Go's Mutex is NOT reentrant — locking twice from the same goroutine deadlocks.\n",[47,68,70],{"class":49,"line":69},4,[47,71,73],{"emptyLinePlaceholder":72},true,"\n",[47,75,77,81,85,88],{"class":49,"line":76},5,[47,78,80],{"class":79},"svdQ7","type",[47,82,84],{"class":83},"sIsaT"," Counter",[47,86,87],{"class":79}," struct",[47,89,91],{"class":90},"ssxIu"," {\n",[47,93,95,98,100,103],{"class":49,"line":94},6,[47,96,97],{"class":90},"    mu    ",[47,99,20],{"class":83},[47,101,102],{"class":90},".",[47,104,105],{"class":83},"Mutex\n",[47,107,109,112],{"class":49,"line":108},7,[47,110,111],{"class":90},"    count ",[47,113,114],{"class":79},"int\n",[47,116,118],{"class":49,"line":117},8,[47,119,120],{"class":90},"}\n",[47,122,124],{"class":49,"line":123},9,[47,125,73],{"emptyLinePlaceholder":72},[47,127,129,132,135,139,142,145,148,151],{"class":49,"line":128},10,[47,130,131],{"class":79},"func",[47,133,134],{"class":90}," (",[47,136,138],{"class":137},"sCrzJ","c ",[47,140,141],{"class":79},"*",[47,143,144],{"class":83},"Counter",[47,146,147],{"class":90},") ",[47,149,150],{"class":83},"Inc",[47,152,153],{"class":90},"() {\n",[47,155,157,160,163],{"class":49,"line":156},11,[47,158,159],{"class":90},"    c.mu.",[47,161,162],{"class":83},"Lock",[47,164,165],{"class":90},"()\n",[47,167,169,172,175,178,181],{"class":49,"line":168},12,[47,170,171],{"class":79},"    defer",[47,173,174],{"class":90}," c.mu.",[47,176,177],{"class":83},"Unlock",[47,179,180],{"class":90},"()  ",[47,182,183],{"class":53},"\u002F\u002F ✅ always defer Unlock — runs even on panic\n",[47,185,187,190],{"class":49,"line":186},13,[47,188,189],{"class":90},"    c.count",[47,191,192],{"class":79},"++\n",[47,194,196],{"class":49,"line":195},14,[47,197,120],{"class":90},[47,199,201],{"class":49,"line":200},15,[47,202,73],{"emptyLinePlaceholder":72},[47,204,206,208,210,212,214,216,218,221,224,227],{"class":49,"line":205},16,[47,207,131],{"class":79},[47,209,134],{"class":90},[47,211,138],{"class":137},[47,213,141],{"class":79},[47,215,144],{"class":83},[47,217,147],{"class":90},[47,219,220],{"class":83},"Get",[47,222,223],{"class":90},"() ",[47,225,226],{"class":79},"int",[47,228,91],{"class":90},[47,230,232,234,236],{"class":49,"line":231},17,[47,233,159],{"class":90},[47,235,162],{"class":83},[47,237,165],{"class":90},[47,239,241,243,245,247],{"class":49,"line":240},18,[47,242,171],{"class":79},[47,244,174],{"class":90},[47,246,177],{"class":83},[47,248,165],{"class":90},[47,250,252,255],{"class":49,"line":251},19,[47,253,254],{"class":79},"    return",[47,256,257],{"class":90}," c.count\n",[47,259,261],{"class":49,"line":260},20,[47,262,120],{"class":90},[47,264,266],{"class":49,"line":265},21,[47,267,73],{"emptyLinePlaceholder":72},[47,269,271],{"class":49,"line":270},22,[47,272,273],{"class":53},"\u002F\u002F ─── RWMutex — multiple readers OR one writer ───\n",[47,275,277,279,282,284],{"class":49,"line":276},23,[47,278,80],{"class":79},[47,280,281],{"class":83}," Cache",[47,283,87],{"class":79},[47,285,91],{"class":90},[47,287,289,291,293,295],{"class":49,"line":288},24,[47,290,97],{"class":90},[47,292,20],{"class":83},[47,294,102],{"class":90},[47,296,297],{"class":83},"RWMutex\n",[47,299,301,304,307,310,313,316],{"class":49,"line":300},25,[47,302,303],{"class":90},"    data  ",[47,305,306],{"class":79},"map",[47,308,309],{"class":90},"[",[47,311,312],{"class":79},"string",[47,314,315],{"class":90},"]",[47,317,318],{"class":79},"string\n",[47,320,322],{"class":49,"line":321},26,[47,323,120],{"class":90},[47,325,327],{"class":49,"line":326},27,[47,328,73],{"emptyLinePlaceholder":72},[47,330,332,334,336,338,340,343,345,347,350,353,356,359,361,364,367],{"class":49,"line":331},28,[47,333,131],{"class":79},[47,335,134],{"class":90},[47,337,138],{"class":137},[47,339,141],{"class":79},[47,341,342],{"class":83},"Cache",[47,344,147],{"class":90},[47,346,220],{"class":83},[47,348,349],{"class":90},"(",[47,351,352],{"class":137},"key",[47,354,355],{"class":79}," string",[47,357,358],{"class":90},") (",[47,360,312],{"class":79},[47,362,363],{"class":90},", ",[47,365,366],{"class":79},"bool",[47,368,369],{"class":90},") {\n",[47,371,373,375,378,381],{"class":49,"line":372},29,[47,374,159],{"class":90},[47,376,377],{"class":83},"RLock",[47,379,380],{"class":90},"()         ",[47,382,383],{"class":53},"\u002F\u002F ✅ multiple readers can hold RLock simultaneously\n",[47,385,387,389,391,394],{"class":49,"line":386},30,[47,388,171],{"class":79},[47,390,174],{"class":90},[47,392,393],{"class":83},"RUnlock",[47,395,165],{"class":90},[47,397,399,402,405],{"class":49,"line":398},31,[47,400,401],{"class":90},"    val, ok ",[47,403,404],{"class":79},":=",[47,406,407],{"class":90}," c.data[key]\n",[47,409,411,413],{"class":49,"line":410},32,[47,412,254],{"class":79},[47,414,415],{"class":90}," val, ok\n",[47,417,419],{"class":49,"line":418},33,[47,420,120],{"class":90},[47,422,424],{"class":49,"line":423},34,[47,425,73],{"emptyLinePlaceholder":72},[47,427,429,431,433,435,437,439,441,444,446,448,450,453,455],{"class":49,"line":428},35,[47,430,131],{"class":79},[47,432,134],{"class":90},[47,434,138],{"class":137},[47,436,141],{"class":79},[47,438,342],{"class":83},[47,440,147],{"class":90},[47,442,443],{"class":83},"Set",[47,445,349],{"class":90},[47,447,352],{"class":137},[47,449,363],{"class":90},[47,451,452],{"class":137},"val",[47,454,355],{"class":79},[47,456,369],{"class":90},[47,458,460,462,464,467],{"class":49,"line":459},36,[47,461,159],{"class":90},[47,463,162],{"class":83},[47,465,466],{"class":90},"()          ",[47,468,469],{"class":53},"\u002F\u002F ✅ exclusive — blocks all readers and writers\n",[47,471,473,475,477,479],{"class":49,"line":472},37,[47,474,171],{"class":79},[47,476,174],{"class":90},[47,478,177],{"class":83},[47,480,165],{"class":90},[47,482,484,487,490],{"class":49,"line":483},38,[47,485,486],{"class":90},"    c.data[key] ",[47,488,489],{"class":79},"=",[47,491,492],{"class":90}," val\n",[47,494,496],{"class":49,"line":495},39,[47,497,120],{"class":90},[47,499,501],{"class":49,"line":500},40,[47,502,73],{"emptyLinePlaceholder":72},[47,504,506],{"class":49,"line":505},41,[47,507,508],{"class":53},"\u002F\u002F ┌──────────────────────────────────────────────────────────────────────┐\n",[47,510,512],{"class":49,"line":511},42,[47,513,514],{"class":53},"\u002F\u002F │ When to use RWMutex vs Mutex:                                        │\n",[47,516,518],{"class":49,"line":517},43,[47,519,520],{"class":53},"\u002F\u002F │   RWMutex: reads vastly outnumber writes AND the critical section     │\n",[47,522,524],{"class":49,"line":523},44,[47,525,526],{"class":53},"\u002F\u002F │            is non-trivial (the RLock overhead is higher than Mutex)  │\n",[47,528,530],{"class":49,"line":529},45,[47,531,532],{"class":53},"\u002F\u002F │   Mutex:   balanced read\u002Fwrite or short critical sections             │\n",[47,534,536],{"class":49,"line":535},46,[47,537,538],{"class":53},"\u002F\u002F │   RWMutex overhead: 2 atomic ops per RLock (vs 1 for Lock)            │\n",[47,540,542],{"class":49,"line":541},47,[47,543,544],{"class":53},"\u002F\u002F │   For write-heavy or short sections, Mutex is faster.                 │\n",[47,546,548],{"class":49,"line":547},48,[47,549,550],{"class":53},"\u002F\u002F └──────────────────────────────────────────────────────────────────────┘\n",[23,552,554,557],{"id":553},"syncwaitgroup-the-race-free-pattern",[18,555,556],{},"sync.WaitGroup"," — The Race-Free Pattern",[35,559,560,961,968],{"language":37},[39,561,563],{"className":41,"code":562,"language":37,"meta":43,"style":43},"\u002F\u002F ❌ ANTI-PATTERN: Add inside the goroutine — races with Wait\nfunc badWait() {\n    var wg sync.WaitGroup\n    for i := 0; i \u003C 5; i++ {\n        go func() {\n            wg.Add(1)     \u002F\u002F ❌ Wait may see counter=0 before Add runs\n            defer wg.Done()\n            work(i)\n        }()\n    }\n    wg.Wait()  \u002F\u002F may return prematurely\n}\n\n\u002F\u002F ✅ CORRECT: Add BEFORE starting the goroutine\nfunc goodWait() {\n    var wg sync.WaitGroup\n    for i := 0; i \u003C 5; i++ {\n        wg.Add(1)       \u002F\u002F ✅ Add before go — Wait won't see 0 prematurely\n        go func(i int) {\n            defer wg.Done()\n            work(i)\n        }(i)\n    }\n    wg.Wait()  \u002F\u002F blocks until all 5 call Done\n}\n\n\u002F\u002F ✅ Batch Add — add all at once, then start goroutines\nfunc batchAdd() {\n    var wg sync.WaitGroup\n    items := make([]int, 100)\n    wg.Add(len(items))  \u002F\u002F add all upfront\n    for i := range items {\n        go func(i int) {\n            defer wg.Done()\n            work(i)\n        }(i)\n    }\n    wg.Wait()\n}\n",[18,564,565,570,579,594,625,635,654,667,675,680,685,698,702,706,711,720,732,754,771,787,797,803,808,812,823,827,831,836,845,857,880,897,911,925,935,941,945,949,957],{"__ignoreMap":43},[47,566,567],{"class":49,"line":50},[47,568,569],{"class":53},"\u002F\u002F ❌ ANTI-PATTERN: Add inside the goroutine — races with Wait\n",[47,571,572,574,577],{"class":49,"line":57},[47,573,131],{"class":79},[47,575,576],{"class":83}," badWait",[47,578,153],{"class":90},[47,580,581,584,587,589,591],{"class":49,"line":63},[47,582,583],{"class":79},"    var",[47,585,586],{"class":90}," wg ",[47,588,20],{"class":83},[47,590,102],{"class":90},[47,592,593],{"class":83},"WaitGroup\n",[47,595,596,599,602,604,608,611,614,617,620,623],{"class":49,"line":69},[47,597,598],{"class":79},"    for",[47,600,601],{"class":90}," i ",[47,603,404],{"class":79},[47,605,607],{"class":606},"snvgF"," 0",[47,609,610],{"class":90},"; i ",[47,612,613],{"class":79},"\u003C",[47,615,616],{"class":606}," 5",[47,618,619],{"class":90},"; i",[47,621,622],{"class":79},"++",[47,624,91],{"class":90},[47,626,627,630,633],{"class":49,"line":76},[47,628,629],{"class":79},"        go",[47,631,632],{"class":79}," func",[47,634,153],{"class":90},[47,636,637,640,643,645,648,651],{"class":49,"line":94},[47,638,639],{"class":90},"            wg.",[47,641,642],{"class":83},"Add",[47,644,349],{"class":90},[47,646,647],{"class":606},"1",[47,649,650],{"class":90},")     ",[47,652,653],{"class":53},"\u002F\u002F ❌ Wait may see counter=0 before Add runs\n",[47,655,656,659,662,665],{"class":49,"line":108},[47,657,658],{"class":79},"            defer",[47,660,661],{"class":90}," wg.",[47,663,664],{"class":83},"Done",[47,666,165],{"class":90},[47,668,669,672],{"class":49,"line":117},[47,670,671],{"class":83},"            work",[47,673,674],{"class":90},"(i)\n",[47,676,677],{"class":49,"line":123},[47,678,679],{"class":90},"        }()\n",[47,681,682],{"class":49,"line":128},[47,683,684],{"class":90},"    }\n",[47,686,687,690,693,695],{"class":49,"line":156},[47,688,689],{"class":90},"    wg.",[47,691,692],{"class":83},"Wait",[47,694,180],{"class":90},[47,696,697],{"class":53},"\u002F\u002F may return prematurely\n",[47,699,700],{"class":49,"line":168},[47,701,120],{"class":90},[47,703,704],{"class":49,"line":186},[47,705,73],{"emptyLinePlaceholder":72},[47,707,708],{"class":49,"line":195},[47,709,710],{"class":53},"\u002F\u002F ✅ CORRECT: Add BEFORE starting the goroutine\n",[47,712,713,715,718],{"class":49,"line":200},[47,714,131],{"class":79},[47,716,717],{"class":83}," goodWait",[47,719,153],{"class":90},[47,721,722,724,726,728,730],{"class":49,"line":205},[47,723,583],{"class":79},[47,725,586],{"class":90},[47,727,20],{"class":83},[47,729,102],{"class":90},[47,731,593],{"class":83},[47,733,734,736,738,740,742,744,746,748,750,752],{"class":49,"line":231},[47,735,598],{"class":79},[47,737,601],{"class":90},[47,739,404],{"class":79},[47,741,607],{"class":606},[47,743,610],{"class":90},[47,745,613],{"class":79},[47,747,616],{"class":606},[47,749,619],{"class":90},[47,751,622],{"class":79},[47,753,91],{"class":90},[47,755,756,759,761,763,765,768],{"class":49,"line":240},[47,757,758],{"class":90},"        wg.",[47,760,642],{"class":83},[47,762,349],{"class":90},[47,764,647],{"class":606},[47,766,767],{"class":90},")       ",[47,769,770],{"class":53},"\u002F\u002F ✅ Add before go — Wait won't see 0 prematurely\n",[47,772,773,775,777,779,782,785],{"class":49,"line":251},[47,774,629],{"class":79},[47,776,632],{"class":79},[47,778,349],{"class":90},[47,780,781],{"class":137},"i",[47,783,784],{"class":79}," int",[47,786,369],{"class":90},[47,788,789,791,793,795],{"class":49,"line":260},[47,790,658],{"class":79},[47,792,661],{"class":90},[47,794,664],{"class":83},[47,796,165],{"class":90},[47,798,799,801],{"class":49,"line":265},[47,800,671],{"class":83},[47,802,674],{"class":90},[47,804,805],{"class":49,"line":270},[47,806,807],{"class":90},"        }(i)\n",[47,809,810],{"class":49,"line":276},[47,811,684],{"class":90},[47,813,814,816,818,820],{"class":49,"line":288},[47,815,689],{"class":90},[47,817,692],{"class":83},[47,819,180],{"class":90},[47,821,822],{"class":53},"\u002F\u002F blocks until all 5 call Done\n",[47,824,825],{"class":49,"line":300},[47,826,120],{"class":90},[47,828,829],{"class":49,"line":321},[47,830,73],{"emptyLinePlaceholder":72},[47,832,833],{"class":49,"line":326},[47,834,835],{"class":53},"\u002F\u002F ✅ Batch Add — add all at once, then start goroutines\n",[47,837,838,840,843],{"class":49,"line":331},[47,839,131],{"class":79},[47,841,842],{"class":83}," batchAdd",[47,844,153],{"class":90},[47,846,847,849,851,853,855],{"class":49,"line":372},[47,848,583],{"class":79},[47,850,586],{"class":90},[47,852,20],{"class":83},[47,854,102],{"class":90},[47,856,593],{"class":83},[47,858,859,862,864,867,870,872,874,877],{"class":49,"line":386},[47,860,861],{"class":90},"    items ",[47,863,404],{"class":79},[47,865,866],{"class":83}," make",[47,868,869],{"class":90},"([]",[47,871,226],{"class":79},[47,873,363],{"class":90},[47,875,876],{"class":606},"100",[47,878,879],{"class":90},")\n",[47,881,882,884,886,888,891,894],{"class":49,"line":398},[47,883,689],{"class":90},[47,885,642],{"class":83},[47,887,349],{"class":90},[47,889,890],{"class":83},"len",[47,892,893],{"class":90},"(items))  ",[47,895,896],{"class":53},"\u002F\u002F add all upfront\n",[47,898,899,901,903,905,908],{"class":49,"line":410},[47,900,598],{"class":79},[47,902,601],{"class":90},[47,904,404],{"class":79},[47,906,907],{"class":79}," range",[47,909,910],{"class":90}," items {\n",[47,912,913,915,917,919,921,923],{"class":49,"line":418},[47,914,629],{"class":79},[47,916,632],{"class":79},[47,918,349],{"class":90},[47,920,781],{"class":137},[47,922,784],{"class":79},[47,924,369],{"class":90},[47,926,927,929,931,933],{"class":49,"line":423},[47,928,658],{"class":79},[47,930,661],{"class":90},[47,932,664],{"class":83},[47,934,165],{"class":90},[47,936,937,939],{"class":49,"line":428},[47,938,671],{"class":83},[47,940,674],{"class":90},[47,942,943],{"class":49,"line":459},[47,944,807],{"class":90},[47,946,947],{"class":49,"line":472},[47,948,684],{"class":90},[47,950,951,953,955],{"class":49,"line":483},[47,952,689],{"class":90},[47,954,692],{"class":83},[47,956,165],{"class":90},[47,958,959],{"class":49,"line":495},[47,960,120],{"class":90},[23,962,964,967],{"id":963},"synconce-lazy-initialization",[18,965,966],{},"sync.Once"," — Lazy Initialization",[35,969,970,1315,1322],{"language":37},[39,971,973],{"className":41,"code":972,"language":37,"meta":43,"style":43},"\u002F\u002F Once.Do runs the function exactly once across ALL goroutines.\n\u002F\u002F Subsequent calls (even concurrent) skip it. The canonical lazy singleton.\n\ntype Database struct {\n    conn *sql.DB\n}\n\nvar (\n    dbOnce sync.Once\n    db     *Database\n)\n\nfunc GetDB() *Database {\n    dbOnce.Do(func() {\n        \u002F\u002F This runs exactly once, even if 100 goroutines call GetDB simultaneously.\n        conn, err := sql.Open(\"postgres\", os.Getenv(\"DSN\"))\n        if err != nil {\n            panic(fmt.Sprintf(\"database init: %v\", err))\n        }\n        db = &Database{conn: conn}\n    })\n    return db\n}\n\n\u002F\u002F ─── Once with error handling ───\n\u002F\u002F Once.Do doesn't support return values. For init that can fail, use a\n\u002F\u002F separate variable:\nvar (\n    initOnce sync.Once\n    initErr  error\n)\n\nfunc InitConfig() error {\n    initOnce.Do(func() {\n        initErr = loadConfig()\n    })\n    return initErr  \u002F\u002F returns the error from the first call (all callers see same)\n}\n",[18,974,975,980,985,989,1000,1015,1019,1023,1031,1043,1053,1057,1061,1077,1091,1096,1129,1145,1170,1175,1190,1195,1202,1206,1210,1215,1220,1225,1231,1242,1250,1254,1258,1272,1285,1297,1301,1311],{"__ignoreMap":43},[47,976,977],{"class":49,"line":50},[47,978,979],{"class":53},"\u002F\u002F Once.Do runs the function exactly once across ALL goroutines.\n",[47,981,982],{"class":49,"line":57},[47,983,984],{"class":53},"\u002F\u002F Subsequent calls (even concurrent) skip it. The canonical lazy singleton.\n",[47,986,987],{"class":49,"line":63},[47,988,73],{"emptyLinePlaceholder":72},[47,990,991,993,996,998],{"class":49,"line":69},[47,992,80],{"class":79},[47,994,995],{"class":83}," Database",[47,997,87],{"class":79},[47,999,91],{"class":90},[47,1001,1002,1005,1007,1010,1012],{"class":49,"line":76},[47,1003,1004],{"class":90},"    conn ",[47,1006,141],{"class":79},[47,1008,1009],{"class":83},"sql",[47,1011,102],{"class":90},[47,1013,1014],{"class":83},"DB\n",[47,1016,1017],{"class":49,"line":94},[47,1018,120],{"class":90},[47,1020,1021],{"class":49,"line":108},[47,1022,73],{"emptyLinePlaceholder":72},[47,1024,1025,1028],{"class":49,"line":117},[47,1026,1027],{"class":79},"var",[47,1029,1030],{"class":90}," (\n",[47,1032,1033,1036,1038,1040],{"class":49,"line":123},[47,1034,1035],{"class":90},"    dbOnce ",[47,1037,20],{"class":83},[47,1039,102],{"class":90},[47,1041,1042],{"class":83},"Once\n",[47,1044,1045,1048,1050],{"class":49,"line":128},[47,1046,1047],{"class":90},"    db     ",[47,1049,141],{"class":79},[47,1051,1052],{"class":83},"Database\n",[47,1054,1055],{"class":49,"line":156},[47,1056,879],{"class":90},[47,1058,1059],{"class":49,"line":168},[47,1060,73],{"emptyLinePlaceholder":72},[47,1062,1063,1065,1068,1070,1072,1075],{"class":49,"line":186},[47,1064,131],{"class":79},[47,1066,1067],{"class":83}," GetDB",[47,1069,223],{"class":90},[47,1071,141],{"class":79},[47,1073,1074],{"class":83},"Database",[47,1076,91],{"class":90},[47,1078,1079,1082,1085,1087,1089],{"class":49,"line":195},[47,1080,1081],{"class":90},"    dbOnce.",[47,1083,1084],{"class":83},"Do",[47,1086,349],{"class":90},[47,1088,131],{"class":79},[47,1090,153],{"class":90},[47,1092,1093],{"class":49,"line":200},[47,1094,1095],{"class":53},"        \u002F\u002F This runs exactly once, even if 100 goroutines call GetDB simultaneously.\n",[47,1097,1098,1101,1103,1106,1109,1111,1115,1118,1121,1123,1126],{"class":49,"line":205},[47,1099,1100],{"class":90},"        conn, err ",[47,1102,404],{"class":79},[47,1104,1105],{"class":90}," sql.",[47,1107,1108],{"class":83},"Open",[47,1110,349],{"class":90},[47,1112,1114],{"class":1113},"sJ6F3","\"postgres\"",[47,1116,1117],{"class":90},", os.",[47,1119,1120],{"class":83},"Getenv",[47,1122,349],{"class":90},[47,1124,1125],{"class":1113},"\"DSN\"",[47,1127,1128],{"class":90},"))\n",[47,1130,1131,1134,1137,1140,1143],{"class":49,"line":231},[47,1132,1133],{"class":79},"        if",[47,1135,1136],{"class":90}," err ",[47,1138,1139],{"class":79},"!=",[47,1141,1142],{"class":606}," nil",[47,1144,91],{"class":90},[47,1146,1147,1150,1153,1156,1158,1161,1164,1167],{"class":49,"line":240},[47,1148,1149],{"class":83},"            panic",[47,1151,1152],{"class":90},"(fmt.",[47,1154,1155],{"class":83},"Sprintf",[47,1157,349],{"class":90},[47,1159,1160],{"class":1113},"\"database init: ",[47,1162,1163],{"class":606},"%v",[47,1165,1166],{"class":1113},"\"",[47,1168,1169],{"class":90},", err))\n",[47,1171,1172],{"class":49,"line":251},[47,1173,1174],{"class":90},"        }\n",[47,1176,1177,1180,1182,1185,1187],{"class":49,"line":260},[47,1178,1179],{"class":90},"        db ",[47,1181,489],{"class":79},[47,1183,1184],{"class":79}," &",[47,1186,1074],{"class":83},[47,1188,1189],{"class":90},"{conn: conn}\n",[47,1191,1192],{"class":49,"line":265},[47,1193,1194],{"class":90},"    })\n",[47,1196,1197,1199],{"class":49,"line":270},[47,1198,254],{"class":79},[47,1200,1201],{"class":90}," db\n",[47,1203,1204],{"class":49,"line":276},[47,1205,120],{"class":90},[47,1207,1208],{"class":49,"line":288},[47,1209,73],{"emptyLinePlaceholder":72},[47,1211,1212],{"class":49,"line":300},[47,1213,1214],{"class":53},"\u002F\u002F ─── Once with error handling ───\n",[47,1216,1217],{"class":49,"line":321},[47,1218,1219],{"class":53},"\u002F\u002F Once.Do doesn't support return values. For init that can fail, use a\n",[47,1221,1222],{"class":49,"line":326},[47,1223,1224],{"class":53},"\u002F\u002F separate variable:\n",[47,1226,1227,1229],{"class":49,"line":331},[47,1228,1027],{"class":79},[47,1230,1030],{"class":90},[47,1232,1233,1236,1238,1240],{"class":49,"line":372},[47,1234,1235],{"class":90},"    initOnce ",[47,1237,20],{"class":83},[47,1239,102],{"class":90},[47,1241,1042],{"class":83},[47,1243,1244,1247],{"class":49,"line":386},[47,1245,1246],{"class":90},"    initErr  ",[47,1248,1249],{"class":79},"error\n",[47,1251,1252],{"class":49,"line":398},[47,1253,879],{"class":90},[47,1255,1256],{"class":49,"line":410},[47,1257,73],{"emptyLinePlaceholder":72},[47,1259,1260,1262,1265,1267,1270],{"class":49,"line":418},[47,1261,131],{"class":79},[47,1263,1264],{"class":83}," InitConfig",[47,1266,223],{"class":90},[47,1268,1269],{"class":79},"error",[47,1271,91],{"class":90},[47,1273,1274,1277,1279,1281,1283],{"class":49,"line":423},[47,1275,1276],{"class":90},"    initOnce.",[47,1278,1084],{"class":83},[47,1280,349],{"class":90},[47,1282,131],{"class":79},[47,1284,153],{"class":90},[47,1286,1287,1290,1292,1295],{"class":49,"line":428},[47,1288,1289],{"class":90},"        initErr ",[47,1291,489],{"class":79},[47,1293,1294],{"class":83}," loadConfig",[47,1296,165],{"class":90},[47,1298,1299],{"class":49,"line":459},[47,1300,1194],{"class":90},[47,1302,1303,1305,1308],{"class":49,"line":472},[47,1304,254],{"class":79},[47,1306,1307],{"class":90}," initErr  ",[47,1309,1310],{"class":53},"\u002F\u002F returns the error from the first call (all callers see same)\n",[47,1312,1313],{"class":49,"line":483},[47,1314,120],{"class":90},[23,1316,1318,1321],{"id":1317},"synccond-condition-variables",[18,1319,1320],{},"sync.Cond"," — Condition Variables",[35,1323,1324,1682,1689],{"language":37},[39,1325,1327],{"className":41,"code":1326,"language":37,"meta":43,"style":43},"\u002F\u002F Cond is for \"wait until a condition is true.\" Less common than channels\n\u002F\u002F but useful for bounded-buffer \u002F producer-consumer patterns.\n\ntype Queue struct {\n    mu    sync.Mutex\n    cond  *sync.Cond\n    items []int\n}\n\nfunc NewQueue() *Queue {\n    q := &Queue{}\n    q.cond = sync.NewCond(&q.mu)  \u002F\u002F Cond is bound to a Mutex\n    return q\n}\n\nfunc (q *Queue) Put(item int) {\n    q.mu.Lock()\n    q.items = append(q.items, item)\n    q.cond.Signal()  \u002F\u002F wake ONE waiting consumer\n    q.mu.Unlock()\n}\n\nfunc (q *Queue) Get() int {\n    q.mu.Lock()\n    defer q.mu.Unlock()\n\n    \u002F\u002F ⚠️ MUST loop — spurious wakeups can occur\n    for len(q.items) == 0 {\n        q.cond.Wait()  \u002F\u002F atomically: unlock mu, block, re-lock on wake\n    }\n    item := q.items[0]\n    q.items = q.items[1:]\n    return item\n}\n\n\u002F\u002F ─── Broadcast vs Signal ───\n\u002F\u002F Signal: wake ONE waiter (use when one item is added)\n\u002F\u002F Broadcast: wake ALL waiters (use when the condition changes for everyone)\n",[18,1328,1329,1334,1339,1343,1354,1364,1378,1385,1389,1393,1409,1423,1447,1454,1458,1462,1489,1498,1511,1524,1532,1536,1540,1562,1570,1581,1585,1590,1607,1619,1623,1639,1652,1659,1663,1667,1672,1677],{"__ignoreMap":43},[47,1330,1331],{"class":49,"line":50},[47,1332,1333],{"class":53},"\u002F\u002F Cond is for \"wait until a condition is true.\" Less common than channels\n",[47,1335,1336],{"class":49,"line":57},[47,1337,1338],{"class":53},"\u002F\u002F but useful for bounded-buffer \u002F producer-consumer patterns.\n",[47,1340,1341],{"class":49,"line":63},[47,1342,73],{"emptyLinePlaceholder":72},[47,1344,1345,1347,1350,1352],{"class":49,"line":69},[47,1346,80],{"class":79},[47,1348,1349],{"class":83}," Queue",[47,1351,87],{"class":79},[47,1353,91],{"class":90},[47,1355,1356,1358,1360,1362],{"class":49,"line":76},[47,1357,97],{"class":90},[47,1359,20],{"class":83},[47,1361,102],{"class":90},[47,1363,105],{"class":83},[47,1365,1366,1369,1371,1373,1375],{"class":49,"line":94},[47,1367,1368],{"class":90},"    cond  ",[47,1370,141],{"class":79},[47,1372,20],{"class":83},[47,1374,102],{"class":90},[47,1376,1377],{"class":83},"Cond\n",[47,1379,1380,1383],{"class":49,"line":108},[47,1381,1382],{"class":90},"    items []",[47,1384,114],{"class":79},[47,1386,1387],{"class":49,"line":117},[47,1388,120],{"class":90},[47,1390,1391],{"class":49,"line":123},[47,1392,73],{"emptyLinePlaceholder":72},[47,1394,1395,1397,1400,1402,1404,1407],{"class":49,"line":128},[47,1396,131],{"class":79},[47,1398,1399],{"class":83}," NewQueue",[47,1401,223],{"class":90},[47,1403,141],{"class":79},[47,1405,1406],{"class":83},"Queue",[47,1408,91],{"class":90},[47,1410,1411,1414,1416,1418,1420],{"class":49,"line":156},[47,1412,1413],{"class":90},"    q ",[47,1415,404],{"class":79},[47,1417,1184],{"class":79},[47,1419,1406],{"class":83},[47,1421,1422],{"class":90},"{}\n",[47,1424,1425,1428,1430,1433,1436,1438,1441,1444],{"class":49,"line":168},[47,1426,1427],{"class":90},"    q.cond ",[47,1429,489],{"class":79},[47,1431,1432],{"class":90}," sync.",[47,1434,1435],{"class":83},"NewCond",[47,1437,349],{"class":90},[47,1439,1440],{"class":79},"&",[47,1442,1443],{"class":90},"q.mu)  ",[47,1445,1446],{"class":53},"\u002F\u002F Cond is bound to a Mutex\n",[47,1448,1449,1451],{"class":49,"line":186},[47,1450,254],{"class":79},[47,1452,1453],{"class":90}," q\n",[47,1455,1456],{"class":49,"line":195},[47,1457,120],{"class":90},[47,1459,1460],{"class":49,"line":200},[47,1461,73],{"emptyLinePlaceholder":72},[47,1463,1464,1466,1468,1471,1473,1475,1477,1480,1482,1485,1487],{"class":49,"line":205},[47,1465,131],{"class":79},[47,1467,134],{"class":90},[47,1469,1470],{"class":137},"q ",[47,1472,141],{"class":79},[47,1474,1406],{"class":83},[47,1476,147],{"class":90},[47,1478,1479],{"class":83},"Put",[47,1481,349],{"class":90},[47,1483,1484],{"class":137},"item",[47,1486,784],{"class":79},[47,1488,369],{"class":90},[47,1490,1491,1494,1496],{"class":49,"line":231},[47,1492,1493],{"class":90},"    q.mu.",[47,1495,162],{"class":83},[47,1497,165],{"class":90},[47,1499,1500,1503,1505,1508],{"class":49,"line":240},[47,1501,1502],{"class":90},"    q.items ",[47,1504,489],{"class":79},[47,1506,1507],{"class":83}," append",[47,1509,1510],{"class":90},"(q.items, item)\n",[47,1512,1513,1516,1519,1521],{"class":49,"line":251},[47,1514,1515],{"class":90},"    q.cond.",[47,1517,1518],{"class":83},"Signal",[47,1520,180],{"class":90},[47,1522,1523],{"class":53},"\u002F\u002F wake ONE waiting consumer\n",[47,1525,1526,1528,1530],{"class":49,"line":260},[47,1527,1493],{"class":90},[47,1529,177],{"class":83},[47,1531,165],{"class":90},[47,1533,1534],{"class":49,"line":265},[47,1535,120],{"class":90},[47,1537,1538],{"class":49,"line":270},[47,1539,73],{"emptyLinePlaceholder":72},[47,1541,1542,1544,1546,1548,1550,1552,1554,1556,1558,1560],{"class":49,"line":276},[47,1543,131],{"class":79},[47,1545,134],{"class":90},[47,1547,1470],{"class":137},[47,1549,141],{"class":79},[47,1551,1406],{"class":83},[47,1553,147],{"class":90},[47,1555,220],{"class":83},[47,1557,223],{"class":90},[47,1559,226],{"class":79},[47,1561,91],{"class":90},[47,1563,1564,1566,1568],{"class":49,"line":288},[47,1565,1493],{"class":90},[47,1567,162],{"class":83},[47,1569,165],{"class":90},[47,1571,1572,1574,1577,1579],{"class":49,"line":300},[47,1573,171],{"class":79},[47,1575,1576],{"class":90}," q.mu.",[47,1578,177],{"class":83},[47,1580,165],{"class":90},[47,1582,1583],{"class":49,"line":321},[47,1584,73],{"emptyLinePlaceholder":72},[47,1586,1587],{"class":49,"line":326},[47,1588,1589],{"class":53},"    \u002F\u002F ⚠️ MUST loop — spurious wakeups can occur\n",[47,1591,1592,1594,1597,1600,1603,1605],{"class":49,"line":331},[47,1593,598],{"class":79},[47,1595,1596],{"class":83}," len",[47,1598,1599],{"class":90},"(q.items) ",[47,1601,1602],{"class":79},"==",[47,1604,607],{"class":606},[47,1606,91],{"class":90},[47,1608,1609,1612,1614,1616],{"class":49,"line":372},[47,1610,1611],{"class":90},"        q.cond.",[47,1613,692],{"class":83},[47,1615,180],{"class":90},[47,1617,1618],{"class":53},"\u002F\u002F atomically: unlock mu, block, re-lock on wake\n",[47,1620,1621],{"class":49,"line":386},[47,1622,684],{"class":90},[47,1624,1625,1628,1630,1633,1636],{"class":49,"line":398},[47,1626,1627],{"class":90},"    item ",[47,1629,404],{"class":79},[47,1631,1632],{"class":90}," q.items[",[47,1634,1635],{"class":606},"0",[47,1637,1638],{"class":90},"]\n",[47,1640,1641,1643,1645,1647,1649],{"class":49,"line":410},[47,1642,1502],{"class":90},[47,1644,489],{"class":79},[47,1646,1632],{"class":90},[47,1648,647],{"class":606},[47,1650,1651],{"class":90},":]\n",[47,1653,1654,1656],{"class":49,"line":418},[47,1655,254],{"class":79},[47,1657,1658],{"class":90}," item\n",[47,1660,1661],{"class":49,"line":423},[47,1662,120],{"class":90},[47,1664,1665],{"class":49,"line":428},[47,1666,73],{"emptyLinePlaceholder":72},[47,1668,1669],{"class":49,"line":459},[47,1670,1671],{"class":53},"\u002F\u002F ─── Broadcast vs Signal ───\n",[47,1673,1674],{"class":49,"line":472},[47,1675,1676],{"class":53},"\u002F\u002F Signal: wake ONE waiter (use when one item is added)\n",[47,1678,1679],{"class":49,"line":483},[47,1680,1681],{"class":53},"\u002F\u002F Broadcast: wake ALL waiters (use when the condition changes for everyone)\n",[23,1683,1685,1688],{"id":1684},"syncpool-object-reuse-to-reduce-gc-pressure",[18,1686,1687],{},"sync.Pool"," — Object Reuse to Reduce GC Pressure",[35,1690,1691,1953,1960],{"language":37},[39,1692,1694],{"className":41,"code":1693,"language":37,"meta":43,"style":43},"\u002F\u002F Pool reuses objects to reduce allocations. Get returns a pooled object\n\u002F\u002F (or calls New if pool is empty); Put returns it for reuse.\n\u002F\u002F ⚠️ Pooled objects can be reclaimed at ANY time (between GC cycles) —\n\u002F\u002F don't store state you need to persist. Reset objects before Put.\n\nvar bufPool = sync.Pool{\n    New: func() any {\n        return new(bytes.Buffer)\n    },\n}\n\nfunc processRequest(data []byte) string {\n    buf := bufPool.Get().(*bytes.Buffer)\n    defer func() {\n        buf.Reset()           \u002F\u002F ⚠️ reset before returning to pool\n        bufPool.Put(buf)\n    }()\n\n    buf.Write(data)\n    return buf.String()\n}\n\n\u002F\u002F ─── When sync.Pool helps ───\n\u002F\u002F   - Short-lived, allocation-heavy objects (buffers, temp structs)\n\u002F\u002F   - High-frequency allocation (thousands per second)\n\u002F\u002F   - The object is the same size\u002Fshape each time\n\u002F\u002F\n\u002F\u002F ─── When it doesn't ───\n\u002F\u002F   - Long-lived objects (pool reclaims them between GCs)\n\u002F\u002F   - Objects that grow (a buffer that grew to 1MB stays 1MB — memory leak)\n\u002F\u002F   - Low-frequency allocation (pool overhead > allocation cost)\n",[18,1695,1696,1701,1706,1711,1716,1720,1740,1754,1774,1779,1783,1787,1811,1836,1844,1858,1868,1873,1877,1888,1900,1904,1908,1913,1918,1923,1928,1933,1938,1943,1948],{"__ignoreMap":43},[47,1697,1698],{"class":49,"line":50},[47,1699,1700],{"class":53},"\u002F\u002F Pool reuses objects to reduce allocations. Get returns a pooled object\n",[47,1702,1703],{"class":49,"line":57},[47,1704,1705],{"class":53},"\u002F\u002F (or calls New if pool is empty); Put returns it for reuse.\n",[47,1707,1708],{"class":49,"line":63},[47,1709,1710],{"class":53},"\u002F\u002F ⚠️ Pooled objects can be reclaimed at ANY time (between GC cycles) —\n",[47,1712,1713],{"class":49,"line":69},[47,1714,1715],{"class":53},"\u002F\u002F don't store state you need to persist. Reset objects before Put.\n",[47,1717,1718],{"class":49,"line":76},[47,1719,73],{"emptyLinePlaceholder":72},[47,1721,1722,1724,1727,1729,1732,1734,1737],{"class":49,"line":94},[47,1723,1027],{"class":79},[47,1725,1726],{"class":90}," bufPool ",[47,1728,489],{"class":79},[47,1730,1731],{"class":83}," sync",[47,1733,102],{"class":90},[47,1735,1736],{"class":83},"Pool",[47,1738,1739],{"class":90},"{\n",[47,1741,1742,1745,1747,1749,1752],{"class":49,"line":108},[47,1743,1744],{"class":90},"    New: ",[47,1746,131],{"class":79},[47,1748,223],{"class":90},[47,1750,1751],{"class":83},"any",[47,1753,91],{"class":90},[47,1755,1756,1759,1762,1764,1767,1769,1772],{"class":49,"line":117},[47,1757,1758],{"class":79},"        return",[47,1760,1761],{"class":83}," new",[47,1763,349],{"class":90},[47,1765,1766],{"class":83},"bytes",[47,1768,102],{"class":90},[47,1770,1771],{"class":83},"Buffer",[47,1773,879],{"class":90},[47,1775,1776],{"class":49,"line":123},[47,1777,1778],{"class":90},"    },\n",[47,1780,1781],{"class":49,"line":128},[47,1782,120],{"class":90},[47,1784,1785],{"class":49,"line":156},[47,1786,73],{"emptyLinePlaceholder":72},[47,1788,1789,1791,1794,1796,1799,1802,1805,1807,1809],{"class":49,"line":168},[47,1790,131],{"class":79},[47,1792,1793],{"class":83}," processRequest",[47,1795,349],{"class":90},[47,1797,1798],{"class":137},"data",[47,1800,1801],{"class":90}," []",[47,1803,1804],{"class":79},"byte",[47,1806,147],{"class":90},[47,1808,312],{"class":79},[47,1810,91],{"class":90},[47,1812,1813,1816,1818,1821,1823,1826,1828,1830,1832,1834],{"class":49,"line":186},[47,1814,1815],{"class":90},"    buf ",[47,1817,404],{"class":79},[47,1819,1820],{"class":90}," bufPool.",[47,1822,220],{"class":83},[47,1824,1825],{"class":90},"().(",[47,1827,141],{"class":79},[47,1829,1766],{"class":83},[47,1831,102],{"class":90},[47,1833,1771],{"class":83},[47,1835,879],{"class":90},[47,1837,1838,1840,1842],{"class":49,"line":195},[47,1839,171],{"class":79},[47,1841,632],{"class":79},[47,1843,153],{"class":90},[47,1845,1846,1849,1852,1855],{"class":49,"line":200},[47,1847,1848],{"class":90},"        buf.",[47,1850,1851],{"class":83},"Reset",[47,1853,1854],{"class":90},"()           ",[47,1856,1857],{"class":53},"\u002F\u002F ⚠️ reset before returning to pool\n",[47,1859,1860,1863,1865],{"class":49,"line":205},[47,1861,1862],{"class":90},"        bufPool.",[47,1864,1479],{"class":83},[47,1866,1867],{"class":90},"(buf)\n",[47,1869,1870],{"class":49,"line":231},[47,1871,1872],{"class":90},"    }()\n",[47,1874,1875],{"class":49,"line":240},[47,1876,73],{"emptyLinePlaceholder":72},[47,1878,1879,1882,1885],{"class":49,"line":251},[47,1880,1881],{"class":90},"    buf.",[47,1883,1884],{"class":83},"Write",[47,1886,1887],{"class":90},"(data)\n",[47,1889,1890,1892,1895,1898],{"class":49,"line":260},[47,1891,254],{"class":79},[47,1893,1894],{"class":90}," buf.",[47,1896,1897],{"class":83},"String",[47,1899,165],{"class":90},[47,1901,1902],{"class":49,"line":265},[47,1903,120],{"class":90},[47,1905,1906],{"class":49,"line":270},[47,1907,73],{"emptyLinePlaceholder":72},[47,1909,1910],{"class":49,"line":276},[47,1911,1912],{"class":53},"\u002F\u002F ─── When sync.Pool helps ───\n",[47,1914,1915],{"class":49,"line":288},[47,1916,1917],{"class":53},"\u002F\u002F   - Short-lived, allocation-heavy objects (buffers, temp structs)\n",[47,1919,1920],{"class":49,"line":300},[47,1921,1922],{"class":53},"\u002F\u002F   - High-frequency allocation (thousands per second)\n",[47,1924,1925],{"class":49,"line":321},[47,1926,1927],{"class":53},"\u002F\u002F   - The object is the same size\u002Fshape each time\n",[47,1929,1930],{"class":49,"line":326},[47,1931,1932],{"class":53},"\u002F\u002F\n",[47,1934,1935],{"class":49,"line":331},[47,1936,1937],{"class":53},"\u002F\u002F ─── When it doesn't ───\n",[47,1939,1940],{"class":49,"line":372},[47,1941,1942],{"class":53},"\u002F\u002F   - Long-lived objects (pool reclaims them between GCs)\n",[47,1944,1945],{"class":49,"line":386},[47,1946,1947],{"class":53},"\u002F\u002F   - Objects that grow (a buffer that grew to 1MB stays 1MB — memory leak)\n",[47,1949,1950],{"class":49,"line":398},[47,1951,1952],{"class":53},"\u002F\u002F   - Low-frequency allocation (pool overhead > allocation cost)\n",[23,1954,1956,1959],{"id":1955},"syncmap-concurrent-map-use-sparingly",[18,1957,1958],{},"sync.Map"," — Concurrent Map (Use Sparingly)",[35,1961,1962,2432,2436,2538,2542,2680,2684],{"language":37},[39,1963,1965],{"className":41,"code":1964,"language":37,"meta":43,"style":43},"\u002F\u002F sync.Map is safe for concurrent use without a mutex.\n\u002F\u002F Optimized for write-rarely\u002Fread-many (caches with few updates).\n\u002F\u002F Uses `any` (no generics — must type-assert on Load).\n\nfunc syncMapDemo() {\n    var m sync.Map\n    m.Store(\"key\", \"value\")\n\n    v, ok := m.Load(\"key\")  \u002F\u002F v is any — must assert: v.(string)\n    if ok {\n        fmt.Println(v.(string))\n    }\n\n    \u002F\u002F LoadOrStore — atomic \"get or set\":\n    actual, loaded := m.LoadOrStore(\"key\", \"default\")\n    \u002F\u002F loaded=false if newly stored, true if existing value returned\n\n    m.Delete(\"key\")\n\n    m.Range(func(k, v any) bool {\n        fmt.Println(k, v)\n        return true  \u002F\u002F continue iteration\n    })\n}\n\n\u002F\u002F ─── Generic concurrent map (usually better than sync.Map) ───\ntype ConcurrentMap[K comparable, V any] struct {\n    mu sync.RWMutex\n    m  map[K]V\n}\n\nfunc (c *ConcurrentMap[K, V]) Get(key K) (V, bool) {\n    c.mu.RLock()\n    defer c.mu.RUnlock()\n    v, ok := c.m[key]\n    return v, ok\n}\n\nfunc (c *ConcurrentMap[K, V]) Set(key K, val V) {\n    c.mu.Lock()\n    defer c.mu.Unlock()\n    c.m[key] = val\n}\n\u002F\u002F Type-safe, often faster than sync.Map for balanced read\u002Fwrite workloads.\n",[18,1966,1967,1972,1977,1982,1986,1995,2009,2029,2033,2056,2064,2079,2083,2087,2092,2115,2120,2124,2137,2141,2171,2180,2190,2194,2198,2202,2207,2237,2248,2264,2268,2272,2315,2323,2333,2342,2349,2353,2357,2396,2404,2414,2423,2427],{"__ignoreMap":43},[47,1968,1969],{"class":49,"line":50},[47,1970,1971],{"class":53},"\u002F\u002F sync.Map is safe for concurrent use without a mutex.\n",[47,1973,1974],{"class":49,"line":57},[47,1975,1976],{"class":53},"\u002F\u002F Optimized for write-rarely\u002Fread-many (caches with few updates).\n",[47,1978,1979],{"class":49,"line":63},[47,1980,1981],{"class":53},"\u002F\u002F Uses `any` (no generics — must type-assert on Load).\n",[47,1983,1984],{"class":49,"line":69},[47,1985,73],{"emptyLinePlaceholder":72},[47,1987,1988,1990,1993],{"class":49,"line":76},[47,1989,131],{"class":79},[47,1991,1992],{"class":83}," syncMapDemo",[47,1994,153],{"class":90},[47,1996,1997,1999,2002,2004,2006],{"class":49,"line":94},[47,1998,583],{"class":79},[47,2000,2001],{"class":90}," m ",[47,2003,20],{"class":83},[47,2005,102],{"class":90},[47,2007,2008],{"class":83},"Map\n",[47,2010,2011,2014,2017,2019,2022,2024,2027],{"class":49,"line":108},[47,2012,2013],{"class":90},"    m.",[47,2015,2016],{"class":83},"Store",[47,2018,349],{"class":90},[47,2020,2021],{"class":1113},"\"key\"",[47,2023,363],{"class":90},[47,2025,2026],{"class":1113},"\"value\"",[47,2028,879],{"class":90},[47,2030,2031],{"class":49,"line":117},[47,2032,73],{"emptyLinePlaceholder":72},[47,2034,2035,2038,2040,2043,2046,2048,2050,2053],{"class":49,"line":123},[47,2036,2037],{"class":90},"    v, ok ",[47,2039,404],{"class":79},[47,2041,2042],{"class":90}," m.",[47,2044,2045],{"class":83},"Load",[47,2047,349],{"class":90},[47,2049,2021],{"class":1113},[47,2051,2052],{"class":90},")  ",[47,2054,2055],{"class":53},"\u002F\u002F v is any — must assert: v.(string)\n",[47,2057,2058,2061],{"class":49,"line":128},[47,2059,2060],{"class":79},"    if",[47,2062,2063],{"class":90}," ok {\n",[47,2065,2066,2069,2072,2075,2077],{"class":49,"line":156},[47,2067,2068],{"class":90},"        fmt.",[47,2070,2071],{"class":83},"Println",[47,2073,2074],{"class":90},"(v.(",[47,2076,312],{"class":79},[47,2078,1128],{"class":90},[47,2080,2081],{"class":49,"line":168},[47,2082,684],{"class":90},[47,2084,2085],{"class":49,"line":186},[47,2086,73],{"emptyLinePlaceholder":72},[47,2088,2089],{"class":49,"line":195},[47,2090,2091],{"class":53},"    \u002F\u002F LoadOrStore — atomic \"get or set\":\n",[47,2093,2094,2097,2099,2101,2104,2106,2108,2110,2113],{"class":49,"line":200},[47,2095,2096],{"class":90},"    actual, loaded ",[47,2098,404],{"class":79},[47,2100,2042],{"class":90},[47,2102,2103],{"class":83},"LoadOrStore",[47,2105,349],{"class":90},[47,2107,2021],{"class":1113},[47,2109,363],{"class":90},[47,2111,2112],{"class":1113},"\"default\"",[47,2114,879],{"class":90},[47,2116,2117],{"class":49,"line":205},[47,2118,2119],{"class":53},"    \u002F\u002F loaded=false if newly stored, true if existing value returned\n",[47,2121,2122],{"class":49,"line":231},[47,2123,73],{"emptyLinePlaceholder":72},[47,2125,2126,2128,2131,2133,2135],{"class":49,"line":240},[47,2127,2013],{"class":90},[47,2129,2130],{"class":83},"Delete",[47,2132,349],{"class":90},[47,2134,2021],{"class":1113},[47,2136,879],{"class":90},[47,2138,2139],{"class":49,"line":251},[47,2140,73],{"emptyLinePlaceholder":72},[47,2142,2143,2145,2148,2150,2152,2154,2157,2159,2162,2165,2167,2169],{"class":49,"line":260},[47,2144,2013],{"class":90},[47,2146,2147],{"class":83},"Range",[47,2149,349],{"class":90},[47,2151,131],{"class":79},[47,2153,349],{"class":90},[47,2155,2156],{"class":137},"k",[47,2158,363],{"class":90},[47,2160,2161],{"class":137},"v",[47,2163,2164],{"class":83}," any",[47,2166,147],{"class":90},[47,2168,366],{"class":79},[47,2170,91],{"class":90},[47,2172,2173,2175,2177],{"class":49,"line":265},[47,2174,2068],{"class":90},[47,2176,2071],{"class":83},[47,2178,2179],{"class":90},"(k, v)\n",[47,2181,2182,2184,2187],{"class":49,"line":270},[47,2183,1758],{"class":79},[47,2185,2186],{"class":606}," true",[47,2188,2189],{"class":53},"  \u002F\u002F continue iteration\n",[47,2191,2192],{"class":49,"line":276},[47,2193,1194],{"class":90},[47,2195,2196],{"class":49,"line":288},[47,2197,120],{"class":90},[47,2199,2200],{"class":49,"line":300},[47,2201,73],{"emptyLinePlaceholder":72},[47,2203,2204],{"class":49,"line":321},[47,2205,2206],{"class":53},"\u002F\u002F ─── Generic concurrent map (usually better than sync.Map) ───\n",[47,2208,2209,2211,2214,2216,2219,2222,2224,2227,2229,2232,2235],{"class":49,"line":326},[47,2210,80],{"class":79},[47,2212,2213],{"class":83}," ConcurrentMap",[47,2215,309],{"class":90},[47,2217,2218],{"class":137},"K",[47,2220,2221],{"class":83}," comparable",[47,2223,363],{"class":90},[47,2225,2226],{"class":137},"V",[47,2228,2164],{"class":83},[47,2230,2231],{"class":90},"] ",[47,2233,2234],{"class":79},"struct",[47,2236,91],{"class":90},[47,2238,2239,2242,2244,2246],{"class":49,"line":331},[47,2240,2241],{"class":90},"    mu ",[47,2243,20],{"class":83},[47,2245,102],{"class":90},[47,2247,297],{"class":83},[47,2249,2250,2253,2255,2257,2259,2261],{"class":49,"line":372},[47,2251,2252],{"class":90},"    m  ",[47,2254,306],{"class":79},[47,2256,309],{"class":90},[47,2258,2218],{"class":83},[47,2260,315],{"class":90},[47,2262,2263],{"class":83},"V\n",[47,2265,2266],{"class":49,"line":386},[47,2267,120],{"class":90},[47,2269,2270],{"class":49,"line":398},[47,2271,73],{"emptyLinePlaceholder":72},[47,2273,2274,2276,2278,2280,2282,2285,2287,2289,2291,2293,2296,2298,2300,2302,2305,2307,2309,2311,2313],{"class":49,"line":410},[47,2275,131],{"class":79},[47,2277,134],{"class":90},[47,2279,138],{"class":137},[47,2281,141],{"class":79},[47,2283,2284],{"class":83},"ConcurrentMap",[47,2286,309],{"class":90},[47,2288,2218],{"class":83},[47,2290,363],{"class":90},[47,2292,2226],{"class":83},[47,2294,2295],{"class":90},"]) ",[47,2297,220],{"class":83},[47,2299,349],{"class":90},[47,2301,352],{"class":137},[47,2303,2304],{"class":83}," K",[47,2306,358],{"class":90},[47,2308,2226],{"class":83},[47,2310,363],{"class":90},[47,2312,366],{"class":79},[47,2314,369],{"class":90},[47,2316,2317,2319,2321],{"class":49,"line":418},[47,2318,159],{"class":90},[47,2320,377],{"class":83},[47,2322,165],{"class":90},[47,2324,2325,2327,2329,2331],{"class":49,"line":423},[47,2326,171],{"class":79},[47,2328,174],{"class":90},[47,2330,393],{"class":83},[47,2332,165],{"class":90},[47,2334,2335,2337,2339],{"class":49,"line":428},[47,2336,2037],{"class":90},[47,2338,404],{"class":79},[47,2340,2341],{"class":90}," c.m[key]\n",[47,2343,2344,2346],{"class":49,"line":459},[47,2345,254],{"class":79},[47,2347,2348],{"class":90}," v, ok\n",[47,2350,2351],{"class":49,"line":472},[47,2352,120],{"class":90},[47,2354,2355],{"class":49,"line":483},[47,2356,73],{"emptyLinePlaceholder":72},[47,2358,2359,2361,2363,2365,2367,2369,2371,2373,2375,2377,2379,2381,2383,2385,2387,2389,2391,2394],{"class":49,"line":495},[47,2360,131],{"class":79},[47,2362,134],{"class":90},[47,2364,138],{"class":137},[47,2366,141],{"class":79},[47,2368,2284],{"class":83},[47,2370,309],{"class":90},[47,2372,2218],{"class":83},[47,2374,363],{"class":90},[47,2376,2226],{"class":83},[47,2378,2295],{"class":90},[47,2380,443],{"class":83},[47,2382,349],{"class":90},[47,2384,352],{"class":137},[47,2386,2304],{"class":83},[47,2388,363],{"class":90},[47,2390,452],{"class":137},[47,2392,2393],{"class":83}," V",[47,2395,369],{"class":90},[47,2397,2398,2400,2402],{"class":49,"line":500},[47,2399,159],{"class":90},[47,2401,162],{"class":83},[47,2403,165],{"class":90},[47,2405,2406,2408,2410,2412],{"class":49,"line":505},[47,2407,171],{"class":79},[47,2409,174],{"class":90},[47,2411,177],{"class":83},[47,2413,165],{"class":90},[47,2415,2416,2419,2421],{"class":49,"line":511},[47,2417,2418],{"class":90},"    c.m[key] ",[47,2420,489],{"class":79},[47,2422,492],{"class":90},[47,2424,2425],{"class":49,"line":517},[47,2426,120],{"class":90},[47,2428,2429],{"class":49,"line":523},[47,2430,2431],{"class":53},"\u002F\u002F Type-safe, often faster than sync.Map for balanced read\u002Fwrite workloads.\n",[23,2433,2435],{"id":2434},"tips-tricks","💡 Tips & Tricks",[2437,2438,2439,2464,2473,2503,2510,2530],"ul",{},[2440,2441,2442,2446,2447,2449,2450,2452,2453,2456,2457,2460,2461,2463],"li",{},[2443,2444,2445],"strong",{},"Idiom",": always pair ",[18,2448,162],{},"\u002F",[18,2451,177],{}," with ",[18,2454,2455],{},"defer"," — ",[18,2458,2459],{},"mu.Lock(); defer mu.Unlock()"," guarantees the unlock runs even on panic. A missing ",[18,2462,177],{}," (early return) deadlocks all other goroutines.",[2440,2465,2466,2468,2469,2472],{},[2443,2467,2445],{},": use ",[18,2470,2471],{},"RWMutex"," only when reads vastly outnumber writes and the critical section is non-trivial — the RWMutex has higher overhead than a Mutex (two atomic ops per RLock). For short sections or write-heavy workloads, a plain Mutex is faster.",[2440,2474,2475,2477,2478,2481,2482,2485,2486,2489,2490,2492,2493,2495,2496,2499,2500,2502],{},[2443,2476,2445],{},": ",[18,2479,2480],{},"wg.Add(n)"," before ",[18,2483,2484],{},"go f()",", not inside ",[18,2487,2488],{},"f"," — there's a race where ",[18,2491,692],{}," sees counter 0 before ",[18,2494,642],{}," runs. ",[18,2497,2498],{},"defer wg.Done()"," inside ",[18,2501,2488],{}," ensures it runs even on panic.",[2440,2504,2505,2468,2507,2509],{},[2443,2506,2445],{},[18,2508,966],{}," for lazy initialization — runs exactly once across all goroutines, without double-checked locking boilerplate. The canonical singleton pattern.",[2440,2511,2512,2514,2515,2517,2518,2520,2521,2523,2524,2526,2527,2529],{},[2443,2513,2445],{},": prefer a ",[18,2516,306],{}," + ",[18,2519,2471],{}," over ",[18,2522,1958],{}," for general concurrent maps — ",[18,2525,1958],{}," is optimized for write-rarely\u002Fread-many (caches) and uses ",[18,2528,1751],{}," (no type safety). A generic map + RWMutex is type-safe and often faster.",[2440,2531,2532,2477,2535,2537],{},[2443,2533,2534],{},"Performance",[18,2536,1687],{}," for short-lived allocation-heavy objects (buffers) — reset before Put, don't store long-lived state. Objects can be reclaimed between GC cycles.",[23,2539,2541],{"id":2540},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2437,2543,2544,2554,2560,2576,2587,2605,2623,2631,2649,2660],{},[2440,2545,2546,2549,2550,2553],{},[2443,2547,2548],{},"Copying a Mutex\u002FWaitGroup\u002FOnce is a bug",": these have internal state. ",[18,2551,2552],{},"go vet"," catches this (\"assignment copies lock value\"). Pass by pointer, never by value.",[2440,2555,2556,2559],{},[2443,2557,2558],{},"Mutex is not reentrant",": locking twice from the same goroutine deadlocks (Go's Mutex has no concept of \"owner\").",[2440,2561,2562,2567,2568,2570,2571,2573,2574,102],{},[2443,2563,2564,2565],{},"Forgetting ",[18,2566,177],{},": a ",[18,2569,162],{}," without ",[18,2572,177],{}," (early return) deadlocks. Use ",[18,2575,2455],{},[2440,2577,2578,2583,2584,2586],{},[2443,2579,2580,2582],{},[18,2581,2471],{}," can starve writers",": if readers continuously hold ",[18,2585,377],{},", a writer may wait indefinitely (Go has anti-starvation, but be aware). For write-heavy, use Mutex.",[2440,2588,2589,2477,2595,2456,2598,2600,2601,2481,2603,102],{},[2443,2590,2591,2594],{},[18,2592,2593],{},"WaitGroup.Add"," inside the goroutine is a race",[18,2596,2597],{},"go func() { wg.Add(1); ... }()",[18,2599,692],{}," may see counter 0. ",[18,2602,642],{},[18,2604,37],{},[2440,2606,2607,2613,2614,2616,2617,2619,2620,2622],{},[2443,2608,2609,2612],{},[18,2610,2611],{},"Once.Do"," blocks concurrent callers",": the first call runs ",[18,2615,2488],{},"; other callers block until it completes. If ",[18,2618,2488],{}," is slow, all concurrent ",[18,2621,1084],{}," calls wait.",[2440,2624,2625,2630],{},[2443,2626,2627,2629],{},[18,2628,1687],{}," objects can be reclaimed",": between GC cycles, pooled objects may be freed. Don't store state you need to persist. Reset before Put.",[2440,2632,2633,2638,2639,2641,2642,2644,2645,2517,2647,102],{},[2443,2634,2635,2637],{},[18,2636,1958],{}," is not generic",": uses ",[18,2640,1751],{}," — type-assert on ",[18,2643,2045],{},". For type safety, use ",[18,2646,306],{},[18,2648,2471],{},[2440,2650,2651,2477,2657,2659],{},[2443,2652,2653,2656],{},[18,2654,2655],{},"Cond.Wait"," must be called with the mutex locked",[18,2658,692],{}," unlocks, waits, re-locks. Calling without the lock is a runtime error.",[2440,2661,2662,2477,2668,2670,2671,2449,2673,2676,2677,102],{},[2443,2663,2664,2667],{},[18,2665,2666],{},"Cond"," spurious wakeups",[18,2669,692],{}," can wake without ",[18,2672,1518],{},[18,2674,2675],{},"Broadcast",". Always loop: ",[18,2678,2679],{},"for !condition { cond.Wait() }",[23,2681,2683],{"id":2682},"quick-quiz","🧠 Quick Quiz",[35,2685,2686,2811],{"language":37},[39,2687,2689],{"className":41,"code":2688,"language":37,"meta":43,"style":43},"type S struct {\n    mu sync.Mutex\n    v  int\n}\n\nfunc f(s S) {  \u002F\u002F ⚠️ s is passed BY VALUE\n    s.mu.Lock()\n    s.v++\n    s.mu.Unlock()\n}\n\nfunc main() {\n    s := S{}\n    f(s)\n}\n",[18,2690,2691,2702,2712,2719,2723,2727,2747,2756,2763,2771,2775,2779,2788,2799,2807],{"__ignoreMap":43},[47,2692,2693,2695,2698,2700],{"class":49,"line":50},[47,2694,80],{"class":79},[47,2696,2697],{"class":83}," S",[47,2699,87],{"class":79},[47,2701,91],{"class":90},[47,2703,2704,2706,2708,2710],{"class":49,"line":57},[47,2705,2241],{"class":90},[47,2707,20],{"class":83},[47,2709,102],{"class":90},[47,2711,105],{"class":83},[47,2713,2714,2717],{"class":49,"line":63},[47,2715,2716],{"class":90},"    v  ",[47,2718,114],{"class":79},[47,2720,2721],{"class":49,"line":69},[47,2722,120],{"class":90},[47,2724,2725],{"class":49,"line":76},[47,2726,73],{"emptyLinePlaceholder":72},[47,2728,2729,2731,2734,2736,2739,2741,2744],{"class":49,"line":94},[47,2730,131],{"class":79},[47,2732,2733],{"class":83}," f",[47,2735,349],{"class":90},[47,2737,2738],{"class":137},"s",[47,2740,2697],{"class":83},[47,2742,2743],{"class":90},") {  ",[47,2745,2746],{"class":53},"\u002F\u002F ⚠️ s is passed BY VALUE\n",[47,2748,2749,2752,2754],{"class":49,"line":108},[47,2750,2751],{"class":90},"    s.mu.",[47,2753,162],{"class":83},[47,2755,165],{"class":90},[47,2757,2758,2761],{"class":49,"line":117},[47,2759,2760],{"class":90},"    s.v",[47,2762,192],{"class":79},[47,2764,2765,2767,2769],{"class":49,"line":123},[47,2766,2751],{"class":90},[47,2768,177],{"class":83},[47,2770,165],{"class":90},[47,2772,2773],{"class":49,"line":128},[47,2774,120],{"class":90},[47,2776,2777],{"class":49,"line":156},[47,2778,73],{"emptyLinePlaceholder":72},[47,2780,2781,2783,2786],{"class":49,"line":168},[47,2782,131],{"class":79},[47,2784,2785],{"class":83}," main",[47,2787,153],{"class":90},[47,2789,2790,2793,2795,2797],{"class":49,"line":186},[47,2791,2792],{"class":90},"    s ",[47,2794,404],{"class":79},[47,2796,2697],{"class":83},[47,2798,1422],{"class":90},[47,2800,2801,2804],{"class":49,"line":195},[47,2802,2803],{"class":83},"    f",[47,2805,2806],{"class":90},"(s)\n",[47,2808,2809],{"class":49,"line":200},[47,2810,120],{"class":90},[14,2812,2813,2814,2816],{},"What does ",[18,2815,2552],{}," report?",[2818,2819,2820,2824,2829,2837,2850,2853,2904],"details",{},[2821,2822,2823],"summary",{},"Answer",[14,2825,2826,2828],{},[18,2827,2552],{}," reports:",[39,2830,2835],{"className":2831,"code":2833,"language":2834},[2832],"language-text","f passes lock by value: S contains sync.Mutex\n","text",[18,2836,2833],{"__ignoreMap":43},[14,2838,2839,2840,2843,2844,2846,2847,2849],{},"Passing ",[18,2841,2842],{},"S"," by value copies the ",[18,2845,28],{}," — the copied mutex has its own (uninitialized) internal state. Locking the copy doesn't protect the original. This is a bug that ",[18,2848,2552],{}," catches.",[14,2851,2852],{},"The fix — pass by pointer:",[39,2854,2856],{"className":41,"code":2855,"language":37,"meta":43,"style":43},"func f(s *S) {\n    s.mu.Lock()\n    defer s.mu.Unlock()\n    s.v++\n}\n",[18,2857,2858,2875,2883,2894,2900],{"__ignoreMap":43},[47,2859,2860,2862,2864,2866,2868,2871,2873],{"class":49,"line":50},[47,2861,131],{"class":79},[47,2863,2733],{"class":83},[47,2865,349],{"class":90},[47,2867,2738],{"class":137},[47,2869,2870],{"class":79}," *",[47,2872,2842],{"class":83},[47,2874,369],{"class":90},[47,2876,2877,2879,2881],{"class":49,"line":57},[47,2878,2751],{"class":90},[47,2880,162],{"class":83},[47,2882,165],{"class":90},[47,2884,2885,2887,2890,2892],{"class":49,"line":63},[47,2886,171],{"class":79},[47,2888,2889],{"class":90}," s.mu.",[47,2891,177],{"class":83},[47,2893,165],{"class":90},[47,2895,2896,2898],{"class":49,"line":69},[47,2897,2760],{"class":90},[47,2899,192],{"class":79},[47,2901,2902],{"class":49,"line":76},[47,2903,120],{"class":90},[14,2905,2906,2909,2910,363,2912,363,2914,2916,2917,2919],{},[2443,2907,2908],{},"The lesson",": types containing ",[18,2911,28],{},[18,2913,556],{},[18,2915,966],{},", etc. must be passed by pointer, never by value. ",[18,2918,2552],{}," catches this automatically.",[23,2921,2923],{"id":2922},"whats-next","📚 What's Next",[14,2925,2926,2927,2932,2933,2936],{},"→ ",[2928,2929,2931],"a",{"href":2930},"\u002Fgo\u002F20-context","20 — Context"," — cancellation trees, deadlines, request-scoped values, and the ",[18,2934,2935],{},"cancel"," leak.",[2938,2939,2940],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":43,"searchDepth":57,"depth":57,"links":2942},[2943,2945,2947],{"id":25,"depth":57,"text":2944},"sync.Mutex and sync.RWMutex — Internals",{"id":553,"depth":57,"text":2946},"sync.WaitGroup — The Race-Free Pattern",{"id":2922,"depth":57,"text":2923},"Mutex\u002FRWMutex internals, WaitGroup race-free usage, Once lazy init, Cond condition variables, Pool allocation reuse, and Map concurrent patterns.","md",{},"\u002Fgo\u002F19-sync-package",{"title":5,"description":2948},"go\u002F19-sync-package","M7u1Fj2wMw60eoaMU5zhYCtvNSBZJ3wvTM8XLDerIFE",1789924648605]