Speed up the initialization phase (#75)

diff --git a/pkg/license/identifier.go b/pkg/license/identifier.go
index e74da75..d9338bb 100644
--- a/pkg/license/identifier.go
+++ b/pkg/license/identifier.go
@@ -19,9 +19,11 @@
 
 import (
 	"fmt"
+	"io/fs"
 	"path/filepath"
 	"regexp"
 	"strings"
+	"sync"
 
 	"github.com/apache/skywalking-eyes/license-eye/assets"
 	"github.com/apache/skywalking-eyes/license-eye/internal/logger"
@@ -37,23 +39,32 @@
 	regexp.MustCompile(`(?i)This project is covered by two different licenses: (?P<license>[^.]+)`),
 }
 
-var normalizedTemplates = make(map[string]string)
+var normalizedTemplates = sync.Map{}
 
 func init() {
+	wg := sync.WaitGroup{}
 	for _, dir := range templatesDirs {
 		files, err := assets.AssetDir(dir)
 		if err != nil {
 			logger.Log.Fatalln("Failed to read license template directory:", dir, err)
 		}
+		wg.Add(len(files))
 		for _, template := range files {
-			name := template.Name()
-			t, err := assets.Asset(filepath.Join(dir, name))
-			if err != nil {
-				logger.Log.Fatalln("Failed to read license template:", dir, err)
-			}
-			normalizedTemplates[dir+"/"+name] = Normalize(string(t))
+			go loadTemplate(&wg, dir, template)
 		}
 	}
+	wg.Wait()
+}
+
+func loadTemplate(wg *sync.WaitGroup, dir string, template fs.DirEntry) {
+	defer wg.Done()
+
+	name := template.Name()
+	t, err := assets.Asset(filepath.Join(dir, name))
+	if err != nil {
+		logger.Log.Fatalln("Failed to read license template:", dir, err)
+	}
+	normalizedTemplates.Store(dir+"/"+name, Normalize(string(t)))
 }
 
 // Identify identifies the Spdx ID of the given license content
@@ -68,17 +79,26 @@
 	}
 
 	content = Normalize(content)
+	logger.Log.Debugf("Normalized content for %+v:\n%+v\n", pkgPath, content)
 
-	for name, license := range normalizedTemplates {
+	result := make(chan string, 1)
+	normalizedTemplates.Range(func(key, value interface{}) bool {
+		name := key.(string)
+		license := value.(string)
+
 		// Should not use `Contains` as a root LICENSE file may include other licenses the project uses,
 		// `Contains` would identify the last one license as the project's license.
 		if strings.HasPrefix(content, license) {
 			name = filepath.Base(name)
-			return strings.TrimSuffix(name, filepath.Ext(name)), nil
+			result <- strings.TrimSuffix(name, filepath.Ext(name))
+			return false
 		}
+		return true
+	})
+	select {
+	case license := <-result:
+		return license, nil
+	default:
+		return "", fmt.Errorf("cannot identify license content")
 	}
-
-	logger.Log.Debugf("Normalized content for %+v:\n%+v\n", pkgPath, content)
-
-	return "", fmt.Errorf("cannot identify license content")
 }