diff --git a/builtin.go b/builtin.go index cd0dd9a..cbb5ca9 100644 --- a/builtin.go +++ b/builtin.go @@ -51,7 +51,7 @@ var builtinFun BuiltinFunctions var builtinSel BuiltinSelections //builtin functions -var builtinFuncMap = map[string]CallFunc{ +var builtinFuncs = map[string]CallFunc{ "absHref": builtinFun.AbsHref, "attr": builtinFun.Attr, "attrConcat": builtinFun.AttrConcat, @@ -94,5 +94,5 @@ var builtinFuncMap = map[string]CallFunc{ // return "Hello", nil // }) func (p *Pagser) RegisterFunc(name string, fn CallFunc) { - p.ctxFuncs[name] = fn + p.mapFuncs.Store(name, fn) } diff --git a/pagser.go b/pagser.go index 0f7ab9d..931225a 100644 --- a/pagser.go +++ b/pagser.go @@ -8,13 +8,18 @@ package pagser -import "errors" +import ( + "errors" + "sync" +) // Pagser the page parser type Pagser struct { - Config Config - ctxTags map[string]*tagTokenizer // tag value => tagTokenizer - ctxFuncs map[string]CallFunc // name => func + Config Config + //ctxTags map[string]*tagTokenizer // tag value => tagTokenizer + mapTags sync.Map //map[string]*tagTokenizer + //ctxFuncs map[string]CallFunc // name => func + mapFuncs sync.Map //map[string]CallFunc } // New create pagser client @@ -31,9 +36,13 @@ func NewWithConfig(cfg Config) (*Pagser, error) { if cfg.FuncSymbol == "" { return nil, errors.New("FuncSymbol must not empty") } - return &Pagser{ - Config: cfg, - ctxTags: make(map[string]*tagTokenizer, 0), - ctxFuncs: builtinFuncMap, - }, nil + p := Pagser{ + Config: cfg, + //mapTags: make(map[string]*tagTokenizer, 0), + //mapFuncs: builtinFuncs, + } + for k, v := range builtinFuncs { + p.mapFuncs.Store(k, v) + } + return &p, nil } diff --git a/parse.go b/parse.go index 244f193..3ff6f7c 100644 --- a/parse.go +++ b/parse.go @@ -72,13 +72,16 @@ func (p *Pagser) doParse(v interface{}, stackRefValues []reflect.Value, selectio continue } - tag, ok := p.ctxTags[tagValue] - if !ok || tag == nil { + cacheTag, ok := p.mapTags.Load(tagValue) + var tag *tagTokenizer + if !ok || cacheTag == nil { tag, err = p.newTag(tagValue) if err != nil { return err } - p.ctxTags[tagValue] = tag + p.mapTags.Store(tagValue, tag) + } else { + tag = cacheTag.(*tagTokenizer) } node := selection @@ -201,8 +204,9 @@ func (p *Pagser) findAndExecFunc(objRefValue reflect.Value, stackRefValues []ref } //global function - if fn, ok := p.ctxFuncs[selTag.FuncName]; ok { - outValue, err := fn(node, selTag.FuncParams...) + if fn, ok := p.mapFuncs.Load(selTag.FuncName); ok { + cfn := fn.(CallFunc) + outValue, err := cfn(node, selTag.FuncParams...) if err != nil { return nil, fmt.Errorf("call registered func %v error: %v", selTag.FuncName, err) } diff --git a/parse_test.go b/parse_test.go index 458fe6a..2be808b 100644 --- a/parse_test.go +++ b/parse_test.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" "strings" + "sync" "testing" "github.com/PuerkitoBio/goquery" @@ -310,3 +311,23 @@ func TestPagser_ParseReader(t *testing.T) { } fmt.Printf("json: %v\n", prettyJson(data)) } + +func TestPagser_RegisterFunc(t *testing.T) { + threads := 1000 + p := New() + var wg sync.WaitGroup + + for i := 0; i < threads; i++ { + wg.Add(1) + go func() { + for j := 0; j < 10; j++ { + for k, v := range builtinFuncs { + p.RegisterFunc(k, v) + } + } + wg.Done() + }() + } + + wg.Wait() +}