Я программирую поискового робота в clojure, и это занимает постоянное время независимо от глубины, которую я придаю функции. Это сама функция. (используется clojure soup, но я думаю, что это не имеет значения)

(defn crawl [source current-depth max-depth]
    (if (= current-depth 0) (write-to-hf "{" false))
    (let [targets (get-links source)]
        (write-to-hf (str ":" source " " (seq targets) "\n") true)
        (if (< current-depth max-depth)
            (map crawl targets (repeat (inc current-depth)) (repeat max-depth))
            (if (= current-depth 0)
                (do (write-to-hf "}" true)
                 targets)
                targets))))

(write-to-hf - это функция, которая записывает данные в файл, поэтому я думаю, это тоже не имеет отношения к проблеме.)

Когда я тестировал свою функцию в REPL, я писал:

(crawl "http://bg.wikipedia.org" 0 1)

Чтобы распечатать все ссылки, требуется около часа, но если я помещу результат в var, это займет меньше секунды.

(def a (crawl "http://bg.wikipedia.org" 0 1))

Мне это кажется нормальным, потому что операции ввода-вывода являются наиболее затратными по времени, но я попытался проверить, сколько времени требуется, чтобы поместить результат в var с большим количеством уровней глубины рекурсии, и похоже, что он постоянный. Даже делаю:

((crawl "http://bg.wikipedia.org" 0 100000000000))

Занимает то же время.

Может кто-нибудь объяснить мне, почему это константа? Я не могу представить, как брать ссылки с миллиардов и больше страниц из Википедии (это огромный веб-сайт с сотнями ссылок на каждой странице) можно сделать менее чем за секунду.

2
mzdravkov 23 Янв 2013 в 22:33

1 ответ

Лучший ответ

Эта строка создает ленивую последовательность просканированных ссылок:

(map crawl targets (repeat (inc current-depth)) (repeat max-depth))

Фактическое сканирование происходит, когда ссылки печатаются (в данном случае REPL), поэтому, когда вы просто сохраняете их в var и не смотрите на них, никакой работы не выполняется. Ничего не делать требует примерно постоянного времени. Оберните эту строку в вызове doall, чтобы сделать его не ленивым

6
Arthur Ulfeldt 23 Янв 2013 в 22:46
Отличный ответ. Для моей выгоды, не могли бы вы объяснить, будет ли dorun здесь более / менее подходящим?
 – 
A. Webb
23 Янв 2013 в 23:17
2
Dorun выбрасывает результаты и сохраняет их.
 – 
Arthur Ulfeldt
23 Янв 2013 в 23:23