【问题标题】:BufferedReader - Block at end of streamBufferedReader - 在流结束时阻塞
【发布时间】:2017-05-03 08:12:57
【问题描述】:

我正在编写一些函数,这些函数使用 clojure.async 来抽象出对套接字的读/写。我的意图是可以将值放入通道中以进行写入,并从通道中弹出以进行读取。这样用户就不用担心Readers/Writers了。

下面的代码在循环中从套接字读取,将它读取的任何内容转发到通道中。通道被返回,因此可以从中读取。我的问题是,当到达流的末尾时,它不是阻塞,而是坐在那里旋转,直到可以读取某些内容。如果我有一些这样的进程正在运行,它会在我的计算机上产生明显的性能问题。

我可以看到解决此问题的最简单方法是以某种方式在 EOF 上设置 BufferedReaderreadLine 块,而不是返回 nil。不过,据我所知,这是不可能的。但这并不让我感到惊讶,因为大多数流的 EOF 阻塞会很奇怪。但是对于套接字流,EOF 似乎没有特定的含义,因为即使到达 EOF 仍然可以接收消息。

一旦到达 EOF,有没有办法防止循环在等待输入时旋转?

(ns chat.so-example
  (:require [clojure.core.async :as a :refer [chan go >!]])
  (:import [java.net Socket SocketException]
           [java.io BufferedReader InputStreamReader InputStream]))

(defn valid-message? [msg]
  (and (some? msg)
       (not (empty? msg))))

(defn new-input-chan [^Socket sock]
  (let [^InputStream in (.getInputStream sock)
        buff-reader     (BufferedReader. (InputStreamReader. in))
        in-chan         (chan)]
    (go
      (try
        (while (.isConnected sock) ; This spins when EOF is reached
          (let [line (.readLine buff-reader)]
            (when (valid-message? line)
              (>! in-chan line))))
        (catch SocketException se
          (#_"Handle exception"))
        (finally
          (a/close! in-chan))))
    in-chan))

【问题讨论】:

  • Rich Hickey 多次表示这不是一个好主意,也不是他对 core.async 的想法。您可能想观看他的 core.async 演讲,以充分了解其背后的基本原理。看看 Zach Tellmans 库,如 manifest 和 aleph,它们实现了您正在寻找的抽象并与 core.async 集成。
  • @LeonGrapenthin 你有上述会谈的链接吗?我想看他们。 :-)

标签: sockets clojure bufferedreader channel


【解决方案1】:

这里唯一旋转的就是你。您正在使用的类中没有任何方法 spin。阅读isConnectedisClosedisInputShutdown 的文档,解决方案应该会变得清晰。它还可以帮助您阅读readLine 的描述,该描述非常清楚在没有更多输入可读取时返回的内容。

【讨论】:

  • 我不太确定这个答案应该回答什么。我确实阅读了getLine 的文档。值得注意的是“如果到达流的末尾,则返回...... null”部分。当返回 null 表示流结束时,(valid-message? line) 变为 false,导致循环失控,因为它不再停在>!。我想知道如何防止快速循环。我意识到我在使用inConnected 时的错误,并尝试只在套接字打开而不是连接时循环,并且行为保持不变。
  • 这也是一个答案链接,你知道它很差。
  • 当你读到流的末尾时,你就在流的末尾。永远不会有另一条消息传入。这就是流结束的意思。这并不意味着“现在什么都没有”。
  • 除非 EOF 在我认为的情况下没有发生,否则我已经能够从套接字读取,即使我已经获得了 EOF。
  • 这根本不会发生。对于套接字,读取过去的“到目前为止已经到达的数据”块。它不会创建 EOF 条件。 EOF 表示您已阅读过去的“所有将存在的数据”。一旦你从readLine 得到 nil,你以后将永远不会得到 nil 以外的任何东西。
【解决方案2】:

java.io.BufferedReader.ready() 方法可以检查是否还有要阅读的内容,即使在 EOF 之后也是如此。此外,Sockets 可以强制转换为BufferedReader,只需使用(clojure.java.io/reader socket)。作家也一样。

不过,我对core.async 不是很熟悉,所以不知道这是否有帮助。

【讨论】:

    猜你喜欢
    • 2019-01-25
    • 2013-10-23
    • 2018-09-26
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多