Clojure core.async.如何用go block里面的open懒洋洋地下载? [英] Clojure core.async. How to download lazily with go block inside with-open?

查看:131
本文介绍了Clojure core.async.如何用go block里面的open懒洋洋地下载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我上一个问题的延续如何在clojure中按比例产生一个惰性序列?

It`s a continuation of my previous question How to produce a lazy sequence by portion in clojure?

我想按部就班从数据库下载数据.最初,我先下载前500行,然后发送请求以获取下500行,依此类推,直到从服务器接收到所有数据为止.

I want download data from a database by portions. Initially I download first 500 rows and then I send a request to fetch next 500 rows and so on until I receive all data from a server.

我写了代码:

(jdbc/atomic conn
 (with-open [cursor (jdbc/fetch-lazy conn [sql_query])]
   (let [lazyseq (jdbc/cursor->lazyseq cursor)
         counter (atom 1)]
     (swap! lazyseq_maps assoc :session_id {:get_next? (chan 1) :over_500 (chan 1) :data []})
     (>!! (:get_next? (:session_id @lazyseq_maps)) true)
     (go
       (doseq [row lazyseq]
         (swap! counter inc)
         (when (<! (:get_next? (:session_id @lazyseq_maps)))
           (swap! lazyseq_maps update-in [:session_id :data] conj row)
           (if (not= 0 (mod @counter 500))
             (>! (:get_next? (:session_id @lazyseq_maps)) true)
             (>! (:over_500 (:session_id @lazyseq_maps)) true))))
        ;
        (close! (:get_next? (:session_id @lazyseq_maps)))
        (close! (:over_500 (:session_id @lazyseq_maps)))
        (.close conn))

     (when (<!! (:over_500 (:session_id @lazyseq_maps))) {:message "over 500 rows"
                                                          :id :session_id
                                                          :data (:data (:session_id @lazyseq_maps))}))))

我在doseq周期的帮助下获取行.当doseq超过500行时,我停放循环(when (<! (:get_next? (:session_id @lazyseq_maps))),并等待来自外部的信号来检索下一个500行.

I fetch rows with help of the doseq cycle. When doseq passed 500 rows I park the cycle (when (<! (:get_next? (:session_id @lazyseq_maps))) and wait for a signal from outside to retrieve next 500 rows.

但是这里我有一个问题.当我发送信号时,程序将引发错误结果集已关闭".即连接在开放范围之外关闭.但是我不明白为什么,因为go块放在了open范围内.您能帮我解决问题吗?

But here I have a problem. When I send the signal, the program throws error "Resultset is closed". I.e connection is closed outside with-open scope. But I don`t understand why, because go block is placed inside with-open scope. Can you help me solve the problem?

推荐答案

(go ...)立即返回,因此(with-open ...)也是如此.

(go ...) returns immediately, therefore, so does (with-open ...).

您可能想用另一种方法来做:

You may want to do it the other way around:

(go (with-open ...))

(go (with-open ...))

但是,请注意,此过程可能会在很长一段时间内保持数据库连接(稀缺资源!),这可能是不希望的,并且与使用轻量级"线程的好处背道而驰,谢谢到go块.以下是一些可供考虑的替代方法:

However, do note that this process will hold on to a database connection (a scarce resource!) for a potentially very long time, which may not be desirable, and kind of goes against the benefit of having 'lightweight' threads thanks to go blocks. Here are some alternatives to consider:

  • 也许您可以为每个批次重新打开数据库连接?
  • 也许您可以急于将整个结果集流式传输到外部存储(例如AWS S3),并让客户端对此进行轮询?

这篇关于Clojure core.async.如何用go block里面的open懒洋洋地下载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆