Повысить эффективность поиска с помощью параллелизма - PullRequest
0 голосов
/ 30 апреля 2018

У меня есть два следующих способа поиска файлов с шаблоном имени (например, *.go для поиска всех файлов go) по пути поиска (например, /Users/username/Desktop). Первый метод использует recursion + goroutine, а второй метод использует очередь, чтобы предотвратить возможную проблему переполнения стека. Из моего тестирования на моем собственном компьютере Desktop, в котором содержится 41 233 файла go, первый метод превосходит второй метод на 4 секунды, что составляет 18 и 22 секунды, соответственно.

Мне было интересно, есть ли лучший способ / параллелизм, чтобы сделать поиск еще более эффективным, потому что я интегрирую поиск в настольное приложение, и я не хочу, чтобы пользователь сидел там и ждал 30 секунд, прежде чем увидеть любые результаты поиска.

type FileSearcher struct {
    Contents []MyFile
}

func (fe *FileSearcher) FindFileRecursive(searchPath, namePattern string) (err error) {

    // get absolute path
    if searchPath, err = filepath.Abs(searchPath); err != nil {
        return
    }
    curFileName := filepath.Base(searchPath)
    if matched, err := filepath.Match(namePattern, curFileName); err == nil && matched {
        if foundFile, err := NewFileFromPath(searchPath); err == nil {
            fe.Contents = append(fe.Contents, *foundFile) // found a match
        }
    } else {
        return
    }

    if isDir, _ := utils.IsDirectory(searchPath); isDir {
        if files, err := ioutil.ReadDir(searchPath); err == nil {
            for _, f := range files {
                fPath := filepath.Join(searchPath, f.Name())
                go fe.FindFileRecursive(fPath, namePattern) // recursive in a goroutine here
            }
        }
    }
    return
}

// FindFile searches for files/directories matching namePattern under searchPath
func (fe *FileSearcher) FindFile(searchPath, namePattern string) (err error) {

    queue := make([]string, 0)
    queue = append(queue, searchPath)

    for len(queue) > 0 {
        path := queue[0]
        curFileName := filepath.Base(path) // get the file/directory name at this path
        queue = queue[1:]                  // pop off the head

        if matched, err := filepath.Match(namePattern, curFileName); err == nil && matched {
            if foundFile, err := NewFileFromPath(path); err == nil {
                fe.Contents = append(fe.Contents, *foundFile) // found a match
            }
        }

        if isDir, _ := utils.IsDirectory(path); isDir {
            if files, err := ioutil.ReadDir(path); err == nil {
                for _, f := range files {
                    fPath := filepath.Join(path, f.Name())
                    queue = append(queue, fPath) // push the new dir path to queue
                }
            }
        }
    }
    return
}
...