Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure中的工作队列_Clojure_Queue - Fatal编程技术网

Clojure中的工作队列

Clojure中的工作队列,clojure,queue,Clojure,Queue,我正在使用Clojure应用程序从web API访问数据。我将发出大量请求,其中许多请求将导致发出更多请求,因此我希望将请求URL保留在一个队列中,以便在后续下载之间留出60秒的时间 以下是我的总结: (def队列延迟(*1000 60));一分钟 (defn报价! [q x] (.最新报价q x) q) (去拿! [q] (.takeFirst q)) (定义我的队列(java.util.concurrent.LinkedBlockingDeque.)) (defn-进程队列项 [项目] (p

我正在使用Clojure应用程序从web API访问数据。我将发出大量请求,其中许多请求将导致发出更多请求,因此我希望将请求URL保留在一个队列中,以便在后续下载之间留出60秒的时间

以下是我的总结:

(def队列延迟(*1000 60));一分钟
(defn报价!
[q x]
(.最新报价q x)
q)
(去拿!
[q]
(.takeFirst q))
(定义我的队列(java.util.concurrent.LinkedBlockingDeque.))
(defn-进程队列项
[项目]
(println“>>”项);将替换为下载`item`
(线程/睡眠队列延迟)
如果我在我的代码中的某个地方包含一个
(future(process queue item(take!my queue))
,那么在REPL中,我可以
(offer!my queue“something”)
,我会立即看到打印的“>>something”。到现在为止,一直都还不错!但是我需要队列在我的程序处于活动状态的整个时间内保持。我刚才提到的
(future…
调用可以在可用的情况下将一个项目从队列中拉出,但我想要的是能够持续监视队列并在可用的情况下调用
处理队列项目的东西

(defn ^:private process
  [queues]
  (loop [[q & qs :as q+qs] queues p (atom true)]
    (when-not (Thread/interrupted)
      (if (or
            (< (count (:promises @work-manager)) (:max-workers @work-manager))
            @p) ; blocks until a worker is available
        (if-let [job (dequeue q)]
          (let [f (future-call #(process-job job))]
            (recur queues (request-promise-from-work-manager)))
          (do
            (Thread/sleep 5000)
            (recur (if (nil? qs) queues qs) p)))
        (recur q+qs (request-promise-from-work-manager))))))
另外,与Clojure通常对并发性的喜爱相反,我希望确保一次只发出一个请求,并且我的程序等待60秒来发出每个后续请求


我认为这是相关的,但我不知道如何适应它来做我想做的事。如何连续轮询队列并确保一次只运行一个请求?

以下是来自的代码片段。它并不完美,但可以让你了解我是如何解决“等待55秒等待第一项”问题的。它基本上是通过承诺来循环的,使用期货来立即处理事情,或者直到承诺“变得”可用

(defn ^:private process
  [queues]
  (loop [[q & qs :as q+qs] queues p (atom true)]
    (when-not (Thread/interrupted)
      (if (or
            (< (count (:promises @work-manager)) (:max-workers @work-manager))
            @p) ; blocks until a worker is available
        (if-let [job (dequeue q)]
          (let [f (future-call #(process-job job))]
            (recur queues (request-promise-from-work-manager)))
          (do
            (Thread/sleep 5000)
            (recur (if (nil? qs) queues qs) p)))
        (recur q+qs (request-promise-from-work-manager))))))
(defn^:私有进程
[排队]
(循环[[q&qs:as q+qs]队列p(atom-true)]
(未连接时(线程/中断)
(如果(或
(<(计数(:promises@work manager))(:max workers@work manager))
@p) ;阻塞,直到有工作人员可用
(如果让[作业(出列q)]
(让[f(未来调用#(处理作业))]
(重复队列(向工作经理请求承诺)))
(做
(线程/睡眠5000)
(重复(如果(nil?qs)队列qs)p)))
(重复q+qs(要求工作经理()()())))

也许你可以做类似的事情?代码不是很好,可能需要重新编写才能使用
lazy seq
,但这只是一个我还没有做过的练习

这很可能是疯狂的,但您始终可以使用这样的函数来创建一个缓慢的延迟序列:

(defn slow-seq [delay-ms coll]
  "Creates a lazy sequence with delays between each element"
  (lazy-seq 
    (if-let [s (seq coll)]
        (do 
          (Thread/sleep delay-ms)
          (cons (first s)
                (slow-seq delay-ms (rest s)))))))
这将基本上确保每个函数调用之间的延迟

您可以将其与以下内容一起使用,以毫秒为单位提供延迟:

(doseq [i (slow-seq 500 (range 10))]
  (println (rand-int 10))
或者,您也可以将函数调用放入序列中,如下所示:

(take 10 (slow-seq 500 (repeatedly #(rand-int 10))))

显然,在上述两种情况下,您都可以用执行/触发下载的任何代码替换
(rand int 10)

我最终推出了自己的小型库,我称之为。您可以在GitHub上阅读完整的文档,但这里是完整的源代码我不打算更新此答案,因此如果您想使用此库,请从GitHub获取源代码。

(ns com.github.bdesham.simple队列)
(定义新队列)
“创建一个新队列。计时器的每个触发器都会导致函数f
与队列中的下一项一起调用。队列开始处理
立即,这实际上意味着要添加到
队列将立即处理。“
[f&opts]
(让[options(进入{:delaytime 1}
(选择键(应用哈希映射选项)[:delaytime]),
delaytime(:delaytime选项),
队列{:queue(java.util.concurrent.LinkedBlockingDeque.)},
任务(代理[java.util.TimerTask][]
(运行[]
(让[项目(.takeFirst(:队列)),
值(:值项),
prom(:承诺项目)]
(如果是舞会
(交付prom(f值))
(f值(()()))),
计时器(java.util.timer.)]
(.计划计时器任务0(int(*1000 delaytime)))
(关联队列:计时器)
(defn取消
“永久停止队列的执行。如果任务已在执行
然后它就安然无恙地进行了。”
[排队]
(.取消(:计时器队列)))
(defn)过程
将项目添加到队列中,直到它被处理为止。返回
(f)项目。”
[队列项目]
(让[答应]
(.offerLast(:队列)
{:价值项目,
:promise prom})
@舞会)
(defn添加
“将项目添加到队列并立即返回。(f item)的值为。”
丢弃,所以如果你使用这个,f可能会有副作用。”
[队列项目]
(.offerLast(:队列)
{:价值项目,
:承诺(无)
使用此队列返回值的示例:

(def url队列(q/新队列slurp:delaytime 30))
(def github(q/进程url队列)https://github.com"))
(定义google(q/进程url队列)http://www.google.com"))
q/process
的调用将被阻塞,因此两个
def
语句之间将有30秒的延迟

仅将此队列用于副作用的示例:

(defn缓存url
[{url:url,filename:filename}]
(spit(java.io.File.filename)
(slurp url)))
(def url队列(q/新队列缓存url:delaytime 30))
(q/添加url队列{:url“https://github.com",
:filename“github.html”});立即返回
(q/添加url队列{:url“https://google.com",
:filename“google.html”});立即返回
没有