2

我正在用 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))

这对我来说看起来很正常,因为 I/O 操作是最耗时的,但我尝试测试将结果放入具有更多递归深度的 var 需要多少时间,并且它似乎是恒定的。甚至在做:

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

需要同样的时间。

有人能解释一下为什么这是一个常数吗?我无法想象如何在不到一秒钟的时间内从维基百科(这是一个巨大的网站,每个页面上都有数百个链接)获取数十亿和更多页面的链接。

4

1 回答 1

6

此行正在生成一个延迟的爬网链接序列:

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

实际的抓取发生在打印链接时(在这种情况下由 REPL),因此当您将它们保存到 var 并且不查看它们时,没有完成任何工作。什么都不做需要大约恒定的时间。将该行包装在调用中doall以使其不懒惰

于 2013-01-23T18:46:06.300 回答