首頁  >  文章  >  後端開發  >  Go 中的並發安全範本:我該怎麼做?

Go 中的並發安全範本:我該怎麼做?

WBOY
WBOY轉載
2024-02-08 21:50:10913瀏覽

Go 中的并发安全模板:我该怎么做?

Go 中的並發安全範本是一個關鍵問題,對於需要在並發環境下進行操作的程式來說,確保資料的安全性是至關重要的。在處理並發時,我們需要採取一些措施來保護共享資源,避免競態條件和資料競爭。在這篇文章中,我將向大家介紹一些常用的並發安全模板,幫助你理解並發安全的概念,並提供一些實踐中的建議。無論是初學者還是有經驗的開發者,都可以從中受益。讓我們一起來探討如何在 Go 中實現並發安全!

問題內容

我有以下電話:

import (
  "text/template"
)

//...

template.new(filepath.base(name)).funcs(templatefunctions).parse(string(asset))

在多個 go 例程中同時調用, 這又會導致以下恐慌:

fatal error: concurrent map iteration and map write

這是回溯:

goroutine 140 [running]:
text/template.addvaluefuncs(0xc00188e000?, 0xc00188e000?)
        [...]/go/src/text/template/funcs.go:88 +0x76
[...]/modules/template.loadembeddedtemplates({0x38ff6cb?, 0xc001cf8060?})
        [...]/src/modules/template/configbased.go:163 +0x749

src/modules/template/configbased.go:163 上的行 上面引用了。它是 template.new(...)

周圍的函數是從 goroutine 同時呼叫的。

這是來自 go/src/text/template/funcs.go:88 的程式碼是否有幫助:

// addvaluefuncs adds to values the functions in funcs, converting them to reflect.values.
func addvaluefuncs(out map[string]reflect.value, in funcmap) {
    for name, fn := range in {
        if !goodname(name) {
            panic(fmt.errorf("function name %q is not a valid identifier", name))
        }
        v := reflect.valueof(fn)
        if v.kind() != reflect.func {
            panic("value for " + name + " not a function")
        }
        if !goodfunc(v.type()) {
            panic(fmt.errorf("can't install method/function %q with %d results", name, v.type().numout()))
        }
        out[name] = v
    }
}

如果 template.new 是並發安全的,為什麼這一行會產生這種恐慌,我該如何正確處理它?

更新。

令人討厭的函數loadembeddedtemplates的程式碼:

func loadEmbeddedTemplates(templateFile string) (*template.Template, error) {
    var t *template.Template

    templateFile = filepath.Join("share", "templates", filepath.Base(templateFile))
    dir := filepath.Dir(templateFile)
    names := assets.GetAssetNames()

    // All templates except + the last one at the end
    filteredNames := []string{}

    for _, name := range names {
        if !strings.HasPrefix(name, dir+"/") || !strings.HasSuffix(name, ".tmpl") {
            continue
        }

        if name != templateFile {
            filteredNames = append(filteredNames, name)
        }
    }

    filteredNames = append(filteredNames, templateFile)

    for _, name := range filteredNames {
        asset, err := assets.GetAsset(name)
        if err != nil {
            return nil, err
        }

        if t == nil {
            t, err = template.New(filepath.Base(name)).Funcs(templateFunctions).Parse(string(asset))
        } else {
            t, err = t.New(filepath.Base(name)).Parse(string(asset))
        }

        if err != nil {
            return nil, err
        }
    }

    return t, nil
}

該函數只是依序載入share/templates/ 中的所有範本

解決方法

您的loadEmbeddedTemplates() 函數存取templateFunctions 變量,將其傳遞給Template.Funcs() ,後者顯然會讀取它(將迭代它)。

並且您可能會在另一個 goroutine 中同時填充它。因此,並發映射寫入錯誤。對它的存取必須同步。

如果可能,請先填滿它,然後才開始使用它(將其傳遞給 Template.Funcs())。這樣就不需要額外的同步或鎖定(並發唯讀總是可以的)。

以上是Go 中的並發安全範本:我該怎麼做?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除