Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.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 为什么xml/会迅速地发出流,而直接写入流却不会_Clojure - Fatal编程技术网

Clojure 为什么xml/会迅速地发出流,而直接写入流却不会

Clojure 为什么xml/会迅速地发出流,而直接写入流却不会,clojure,Clojure,我正在尝试将文本以小块的形式写入流,当我将XML流编写器指向输出流(它立即开始发送数据)然后尝试写入一些文本,然后刷新它,直到流关闭为止,它不会发送任何内容时,这一工作正常 (defn data "Download a 5MB file and parse it" [] (-> "http://www.cs.washington.edu/research/xmldatasets/data/tpc-h/orders.xml" URL. .openStrea

我正在尝试将文本以小块的形式写入流,当我将XML流编写器指向输出流(它立即开始发送数据)然后尝试写入一些文本,然后刷新它,直到流关闭为止,它不会发送任何内容时,这一工作正常

(defn data
  "Download a 5MB file and parse it"
  []
  (-> "http://www.cs.washington.edu/research/xmldatasets/data/tpc-h/orders.xml"
      URL.
      .openStream
      xml/parse))

(defn send-stuff [request]
  (condp = (:uri request)
    "/text" (response/response
             (ring-io/piped-input-stream
              #(let [w (io/make-writer % {:encoding "UTF-8"})]
                 (.write w "start\n")
                 (.flush w)
                 (Thread/sleep 1000)
                 (.write w "done\n")
                 (.flush w))))
    "/xml"  (response/response
             (ring-io/piped-input-stream
              #(->> (io/make-writer % {:encoding "UTF-8"})
                    (xml/emit (data))
                    .flush)))))

(comment
  (def server (jetty/run-jetty #'send-stuff {:port 8888 :join? false}))
  (.stop server))
用旋度测试,如下所示:

curl localhost:8888/text
静静地坐在那里整整一秒钟,然后回来

start
done
我希望看到“开始”,然后一秒钟后“完成”,而不是一秒钟的延迟,然后两者

和使用

curl localhost:8888/xml
立即开始流式传输刺眼的XML(很抱歉,个人偏见潜入其中;-)

-- 编辑 我已经确认了jetty输出缓冲区的问题,因为如果我将该缓冲区设置得很小,它就会消失:

(def server (jetty/run-jetty #'send-stuff {:output-buffer-size 1 :port 8888 :join? false}))

当然,在许多情况下,将输出缓冲区设置为1是一个坏主意。

您正在调用的
.flush
不是在用于HTTP响应的流上,而是在流上

当您查看时,您会注意到,它只通知所有等待从连接的PipedInputStream读取的线程,并不意味着刷新到底层HTTP响应流

行为上的差异是由响应数据大小引起的。如果将示例更改为使用小型XML数据,则行为将是相同的:

(defn data
  []
  (-> "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a>1</a>"
      (.getBytes)
      (ByteArrayInputStream.)
      (xml/parse)))


(defn send-stuff [request]
  (condp = (:uri request)
    "/text" (response/response
              (ring-io/piped-input-stream
                #(let [w (io/make-writer % {:encoding "UTF-8"})]
                   (.write w "start\n")
                   (.flush w)
                   (Thread/sleep 1000)
                   (.write w "done\n")
                   (.flush w))))
    "/xml"  (response/response
              (ring-io/piped-input-stream
                #(let [w (io/make-writer % {:encoding "UTF-8"})]
                   (xml/emit (data) w)
                   (.flush w)
                   (Thread/sleep 1000)
                   (xml/emit (data) w)
                   (.flush w))))))

在它开始配管之前还是之后?我测试的目的是什么?嗯,关于如何进入环并刷新那里的输出缓冲区,有什么想法吗?我认为您可以使用自己的流机制(而不是管道输入/输出流)并通过扩展
ring.core.protocols/StreamableResponseBody
协议将其插入
write body to stream
函数中的HTTP响应输出流。我最近提到过你有多棒吗?值得注意的是,刷新连接对的另一端(通过将其包装在另一个中间件中)也不能解决这个问题我假设这个例子对你有效,尽管我在返回相同的结果时遇到了一些问题,即使我删除了扩展协议块。
(ns so43769408
  (:require [ring.adapter.jetty :as jetty]
            [clojure.java.io :as io]
            [ring.util.response :as response]
            [ring.core.protocols :as protocols])
  (:import (java.io OutputStream)
           (java.util.concurrent LinkedBlockingQueue)))

(extend-protocol protocols/StreamableResponseBody
  LinkedBlockingQueue
  (write-body-to-stream [output-queue _ ^OutputStream output-stream]
    (with-open [out (io/writer output-stream)]
      (loop [chunk (.take output-queue)]
        (when-not (= chunk ::EOF)
          (.write out (str chunk))
          (.flush out)
          (recur (.take output-queue)))))))


(defn send-stuff [request]
  (response/response
    (let [output-queue (LinkedBlockingQueue.)]
      (future
        (.put output-queue "start\n")
        (Thread/sleep 1000)
        (.put output-queue "end\n")
        (.put output-queue ::EOF))
      output-queue)))

(comment
  (def server (jetty/run-jetty #'send-stuff {:port 8888 :join? false}))
  (.stop server))