17

レイジー seq は常にチャンクされているという印象を受けました。

=> (take 1 (map #(do (print \.) %) (range)))
(................................0)

によって返されるレイジー seq はrange32 要素のチャンクに分割されるため、予想どおり 32 ドットが出力されます。ただし、代わりにrange自分の関数でこれを試すとget-rss-feeds、遅延シーケンスはチャンクされなくなります。

=> (take 1 (map #(do (print \.) %) (get-rss-feeds r)))
(."http://wholehealthsource.blogspot.com/feeds/posts/default")

ドットが 1 つだけ出力されるので、返される lazy-seq はget-rss-feedsチャンクされていないと思います。それはそう:

=> (chunked-seq? (seq (range)))
true

=> (chunked-seq? (seq (get-rss-feeds r)))
false

のソースは次のget-rss-feedsとおりです。

(defn get-rss-feeds
  "returns a lazy seq of urls of all feeds; takes an html-resource from the enlive library"
  [hr]
  (map #(:href (:attrs %))
       (filter #(rss-feed? (:type (:attrs %))) (html/select hr [:link])))

そのため、チャンク性は、レイジー seq の生成方法に依存するようです。関数のソースをのぞき見したところrange、「分厚い」方法で実装されているというヒントがあります。だから私はこれがどのように機能するかについて少し混乱しています。誰かが明確にしてもらえますか?


これが私が知る必要がある理由です。

次のコードが必要です。(get-rss-entry (get-rss-feeds h-res) url)

を呼び出すとget-rss-feeds、調べる必要のあるフィードの URL の遅延シーケンスが返されます。

への呼び出しget-rss-entryは、特定のエントリ (:link フィールドが get-rss-entry の 2 番目の引数と一致する) を探します。によって返された遅延シーケンスを調べますget-rss-feeds。各項目を評価するには、新しい RSS フィードを取得するためにネットワーク経由で http 要求が必要です。http リクエストの数を最小限に抑えるには、シーケンスを 1 つずつ調べて、一致したらすぐに停止することが重要です。

コードは次のとおりです。

(defn get-rss-entry
  [feeds url]
  (ffirst (drop-while empty? (map #(entry-with-url % url) feeds))))

entry-with-url一致の遅延シーケンスを返すか、一致がない場合は空のシーケンスを返します。

これをテストしたところ、正しく動作しているようです (一度に 1 つのフィード URL を評価します)。しかし、どこかで、どういうわけか「分厚い」方法で動作し始め、一度に 32 個のフィードを評価し始めるのではないかと心配しています。here で説明されているように、チャンキーな動作を回避する方法があることは知っていますが、この場合は必要ではないようです。

非慣用的にレイジー seq を使用していますか? ループ/再帰はより良い選択肢でしょうか?

4

3 に答える 3

11

あなたが心配するのは正しいです。パラメータがチャンクされたseqを返すコレクションである場合、厳密に必要以上get-rss-entryに呼び出すことになります。たとえば、がベクトルの場合、一度にチャンク全体を操作します。entry-with-urlfeedsfeedsmap

この問題は、第 12 章で関数が定義されている Fogus のJoy of Clojureで直接対処されています。seq1

(defn seq1 [s]
  (lazy-seq
    (when-let [[x] (seq s)]
      (cons x (seq1 (rest s)))))) 

を呼び出す直前に、可能な限り怠惰にしたいことがわかっている場合に、この権利を使用できますentry-with-url

(defn get-rss-entry
  [フィード URL]
  (ffirst (drop-while empty? (map #(entry-with-url % url) ( seq1 feeds)))))
于 2012-12-27T19:13:26.323 に答える
5

レイジー seq は常にチャンクされるとは限りません- それは生成方法に依存します。

たとえば、この関数によって生成されたレイジー seq はチャンクされません。

(defn integers-from [n]
  (lazy-seq (cons n (do (print \.) (integers-from (inc n))))))

(take 3 (integers-from 3))
=> (..3 .4 5)

しかし、他の多くの clojure 組み込み関数は、パフォーマンス上の理由からチャンク化された seq を生成します (例: range ) 。

于 2012-09-18T15:44:25.287 に答える
4

上記のように、チャンキングの曖昧さによっては賢明ではないようです。チャンク化しないことが本当に必要な場合は、明示的に「チャンク化を解除」することも賢明です。これは、他の時点で、チャンク化する方法でコードが変更された場合、問題が発生しないためです。別の注意点として、アクションを順次実行する必要がある場合、エージェントはダウンロード関数をエージェントに送信できる優れたツールであり、関数の評価方法に関係なく、一度に 1 つずつ実行されます。ある時点でpmap、シーケンスが必要になる場合があります。その場合、アンチャンクでさえ機能しませんが、atom の使用は引き続き正しく機能します。

于 2012-09-13T18:30:12.920 に答える