Clojure http kit get请求在多个异步调用上卡住

Clojure http kit get请求在多个异步调用上卡住,clojure,http-kit,Clojure,Http Kit,我创建了一个小示例来突出问题: (->> (range 0 4) (mapv (fn [i] (http/get "http://http-kit.org/" (fn [res] (info "first callback") (let [res2 @(http/get "http://http-kit.

我创建了一个小示例来突出问题:

(->> (range 0 4)
     (mapv (fn [i]
             (http/get "http://http-kit.org/"
                       (fn [res]
                         (info "first callback")
                         (let [res2 @(http/get "http://http-kit.org/")]
                           (info "second callback ")))))))
打印4s第一次回拨消息时卡住了

如果我将范围更改为0..3,它将工作,同步版本也工作

更新:


(info)
是一个
tauenso.timber
日志库

我目前的假设是,您会因为耗尽线程池而陷入死锁:

  • 您可以为每个外部http/get创建一个线程
  • 如果创建的请求少于线程池中的可用线程,则至少有一个内部
    http/get
    (这将需要一个新线程)
  • 或者,如果在耗尽线程池之前完成了第一个请求
  • 一旦线程池中没有更多线程,内部的
    http/get
    就无法运行 保养
  • 由于内部请求无法完成,外部请求将永远被卡住
  • 您可以使用peek
    http/default pool
    检查线程池http工具包的状态。在那里,您可以看到如下内容:

    #object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 0, queued tasks = 0, completed tasks = 24]"]
    
    当你没有陷入僵局的时候。或

    #object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 8, queued tasks = 8, completed tasks = 28]"]
    
    当你这么做的时候

    我已经在我的机器上进行了测试(显示8为
    (.availableProcessors(Runtime/getRuntime))
    ),我得到了上面的结果。当我运行超过8个请求时,我陷入了僵局


    关于

    我目前的假设是,通过耗尽线程池,您会陷入死锁:

  • 您可以为每个外部http/get创建一个线程
  • 如果创建的请求少于线程池中的可用线程,则至少有一个内部
    http/get
    (这将需要一个新线程)
  • 或者,如果在耗尽线程池之前完成了第一个请求
  • 一旦线程池中没有更多线程,内部的
    http/get
    就无法运行 保养
  • 由于内部请求无法完成,外部请求将永远被卡住
  • 您可以使用peek
    http/default pool
    检查线程池http工具包的状态。在那里,您可以看到如下内容:

    #object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 0, queued tasks = 0, completed tasks = 24]"]
    
    当你没有陷入僵局的时候。或

    #object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 8, queued tasks = 8, completed tasks = 28]"]
    
    当你这么做的时候

    我已经在我的机器上进行了测试(显示8为
    (.availableProcessors(Runtime/getRuntime))
    ),我得到了上面的结果。当我运行超过8个请求时,我陷入了僵局


    关于

    这看起来像是由于http kit客户端线程池在回调函数完成之前不会释放线程而导致的问题。因此,它最终会耗尽线程

    因此,我开始思考如何使回调函数更快,并提出了以下解决方案:

    我已经为http kit client get创建了异步包装函数,它使用回调中的
    clojure.core.async/chan
    快速将结果放入通道,然后等待结果并执行重回调:

    (defn async-http-get
      [url opts callback]
      (let [channel (chan)]
        (http/get url opts #(go (>! channel %)))
        (go (callback (<! channel)))
        nil))
    

    问题似乎是由于http kit客户端线程池在回调函数完成之前不会释放线程造成的。因此,它最终会耗尽线程

    因此,我开始思考如何使回调函数更快,并提出了以下解决方案:

    我已经为http kit client get创建了异步包装函数,它使用回调中的
    clojure.core.async/chan
    快速将结果放入通道,然后等待结果并执行重回调:

    (defn async-http-get
      [url opts callback]
      (let [channel (chan)]
        (http/get url opts #(go (>! channel %)))
        (go (callback (<! channel)))
        nil))
    

    我认为运行时没有问题。你得到了一个由4个寓言组成的向量,打印了4个“第一次回调”,打印了4个“第二次回调”。作为一个合理性检查,请记住
    (范围0 4)
    是4个元素,而不是5个元素。@Josh您能尝试将范围更改为10个元素吗?@Josh我认为它可能因不同的计算机而异,具体取决于CPU核。对我来说,我只是重新启动了我的mac,得到了4个derefables的响应,4个“首次回调”被打印出来,然后被卡住了。我在运行时没有看到任何问题。你得到了一个由4个寓言组成的向量,打印了4个“第一次回调”,打印了4个“第二次回调”。作为一个合理性检查,请记住
    (范围0 4)
    是4个元素,而不是5个元素。@Josh您能尝试将范围更改为10个元素吗?@Josh我认为它可能因不同的计算机而异,具体取决于CPU核。对我来说,我刚刚重新启动了我的mac电脑,得到了4个derefables的响应,4个“first callback”被打印出来然后卡住。是的,我还认为这是一个问题,你能重现这个问题吗?是的,在我的框中,
    (.AvailableProcessor(Runtime/getRuntime))
    为8,如果我运行8个以上的请求,它们就会卡住。是的,我还认为这是一个问题,你能重现这个问题吗?是的,在我的框中,
    (.availableProcessor(Runtime/getRuntime))
    为8,如果我运行8个以上的请求,它们就会卡住。