5
\$\begingroup\$

I have created a router/micro-framework. I have split my code into multiple files by responsibility. All files are in the same directory. Would you recommend any way of improving it ? The most important one for a performance is a tree.go file.

This is a benchmark results for 4 cors CPU.

$ go test -bench=. -cpu=4
BenchmarkStrict1-4               3000000           525 ns/op
BenchmarkStrict2-4               2000000           583 ns/op
BenchmarkStrict3-4               2000000           631 ns/op
BenchmarkStrict5-4               2000000           749 ns/op
BenchmarkStrict10-4              2000000           995 ns/op
BenchmarkStrict100-4              300000          5525 ns/op
BenchmarkStrictParallel1-4       5000000           285 ns/op
BenchmarkStrictParallel2-4      10000000           270 ns/op
BenchmarkStrictParallel3-4       5000000           306 ns/op
BenchmarkStrictParallel5-4       5000000           298 ns/op
BenchmarkStrictParallel10-4      3000000           451 ns/op
BenchmarkStrictParallel100-4     1000000          1913 ns/op
BenchmarkRegexp1-4               1000000          1121 ns/op
BenchmarkRegexp2-4               1000000          1802 ns/op
BenchmarkRegexp3-4               1000000          2200 ns/op
BenchmarkRegexp5-4                500000          3218 ns/op
BenchmarkRegexp10-4               300000          5993 ns/op
BenchmarkRegexp100-4               30000         51510 ns/op
BenchmarkRegexpParallel1-4       2000000           697 ns/op
BenchmarkRegexpParallel2-4       1000000          1003 ns/op
BenchmarkRegexpParallel3-4       1000000          1413 ns/op
BenchmarkRegexpParallel5-4       1000000          1613 ns/op
BenchmarkRegexpParallel10-4       500000          2856 ns/op
BenchmarkRegexpParallel100-4      100000         22202 ns/op

The output BenchmarkStrict1-4 3000000 525 ns/op means that the loop ran 3000000 times at a speed of 525 ns per loop. Each benchmark name BenchmarkStrict5-4 means that test used a strict or regexp route path for each node with a nested level 5. Where 4 stands for CPU number.

For more details take a look benchmark_test.go

Do you know how can i make it faster ? But maybe there are some things along where i can improve my code/logic ?

tree.go

package goserver

import (
    "regexp"
    "strings"
)

type (
    node struct {
        path     string
        regexp   *regexp.Regexp
        route    *route
        parent   *node
        children tree
        params   uint8
    }
    tree map[string]*node
)

func (n *node) isRoot() bool {
    return n.parent == nil
}

func (n *node) isLeaf() bool {
    return len(n.children) == 0
}

func (n *node) regexpToString() string {
    if n.regexp == nil {
        return ""
    }
    return n.regexp.String()
}

func (n *node) setRegexp(exp string) {
    reg, err := regexp.Compile(exp)
    if err == nil {
        n.regexp = reg
    }
}

func (n *node) child(paths []string) (*node, Params) {
    if len(paths) > 0 && paths[0] != "" {
        if child := n.children[paths[0]]; child != nil {
            return child.child(paths[1:])
        }

        for path, child := range n.children {
            if len(path) > 0 && path[:1] == ":" {
                if child.regexp == nil || child.regexp.MatchString(paths[0]) {
                    node, params := child.child(paths[1:])
                    if node != nil && node.params > 0 {
                        params[node.params-1].Key = strings.Split(path, ":")[1]
                        params[node.params-1].Value = paths[0]
                    }

                    return node, params
                }
            }
        }
    } else if len(paths) == 0 {
        return n, make(Params, n.params)
    }
    return nil, make(Params, 0)
}

func (n *node) addChild(paths []string) *node {
    if len(paths) > 0 && paths[0] != "" {
        if n.children[paths[0]] == nil {
            n.children[paths[0]] = newNode(n, paths[0])
        }
        return n.children[paths[0]].addChild(paths[1:])
    }

    return n
}

func (n *node) setRoute(r *route) {
    n.route = r
}

func newNode(root *node, path string) *node {
    n := &node{
        path:     path,
        parent:   root,
        children: make(tree),
    }

    if root != nil {
        n.params = root.params
    }

    if len(n.path) > 0 && path[:1] == ":" {
        n.params++
        if parts := strings.Split(n.path, ":"); len(parts) == 3 {
            n.setRegexp(parts[2])
        }
    }

    return n
}

func newRoot(path string) *node {
    return newNode(nil, path)
}
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.