Lazily Chunking网络调用返回一系列数据

时间:2014-04-01 19:08:04

标签: networking clojure amazon-s3 chunking

我试图建立一个懒惰的seq,根据需要从aws S3中提取数据(通过amazonica库)。 我已经得到了以下代码,几乎可以满足我的需求,但是需要再多做一次网络调用。 (如果有更多可用数据,它总是实现一次递归调用)

编辑:感谢Alex,指出即使网络电话没有实现,我的println也会被调用。此代码现在可以按需执行。那么问题就是有更好的方法吗?

(defn chunked-list-objects-seq
  "Returns a listing of objects in a bucket, with given prefix. These
are lazily chunked, to avoid unneeded network calls.
opts are :bucket-name :prefix :next-marker"
  [cred opts]
  (lazy-seq
   (let [response (s3/list-objects cred opts)
         chunk-size (count (:object-summaries response))]
     (println "pulling from network")
     (chunk-cons
      (let [buffer (chunk-buffer chunk-size)]
        (dotimes [i chunk-size]
          (chunk-append buffer (nth (:object-summaries response) i)))
        (chunk buffer))
      (if (:truncated? response) 
            (chunked-list-objects-seq cred (assoc opts :next-marker (:next-marker response)))
        nil)))))

以上代码改编自" Clojure高性能编程"皮克。 28(自定义分块)

调用它看起来像这样:

user> (time (pprint (count (take 990 (chunked-list-objects-seq cred {:bucket-name "bucket-name" :prefix "path-prefix/"})))))
=> pulling from network
   990
   "Elapsed time: 2009.723 msecs"

(当桶中的项目超过1k时,AWS似乎想要返回1k块)

当然还有其他方法可以做到这一点,(原子和未来的实现会浮现在脑海中),但这似乎最适合seq的接口。

所以基本上,可以修复此代码,不进行不必要的网络调用,这是一个很好的方法吗?

1 个答案:

答案 0 :(得分:2)

我认为使用通过网络获取数据块的分块进行延迟序列是一种非常合理的方法 - 唯一需要注意的是,如果S3客户端代码恰好依赖于设置任何动态绑定,则需要格外小心

您的初始代码在调用之外有println来设置lazy-seq以获取下一个数据块,因此无论下一个块是否实际被提取,您都会看到打印的消息。让println更接近list-objects的通话,可以让您更好地了解网络请求何时发出。