0

I'm trying to read bytes from input-stream and it much slower than reading chars with reader. I can't figure out why it is so. Look at the test:

(defn r1
  [input]
  (loop []
    (when-not (= -1 (.read ^java.io.InputStream input))
      (recur))))

(defn r2
  [input]
  (loop []
    (when-not (.read input)
      (recur))))

(dotimes [_ 10] 
   (time (with-open [is (clojure.java.io/input-stream "15mb.log")]
     (r1 is))))

"Elapsed time: 111.608991 msecs"
"Elapsed time: 95.45663 msecs"
"Elapsed time: 148.789867 msecs"
"Elapsed time: 97.580527 msecs"
"Elapsed time: 113.093759 msecs"
"Elapsed time: 108.306019 msecs"
"Elapsed time: 107.71069 msecs"
"Elapsed time: 104.833343 msecs"
"Elapsed time: 174.701027 msecs"
"Elapsed time: 141.969629 msecs"

(dotimes [_ 10]
   (time (with-open [r (clojure.java.io/reader "15mb.log")]
      (r2 r))))

"Elapsed time: 0.635769 msecs"
"Elapsed time: 0.422315 msecs"
"Elapsed time: 0.355953 msecs"
"Elapsed time: 0.336128 msecs"
"Elapsed time: 0.333523 msecs"
"Elapsed time: 0.339613 msecs"
"Elapsed time: 0.329693 msecs"
"Elapsed time: 0.234213 msecs"
"Elapsed time: 0.209742 msecs"
"Elapsed time: 0.199334 msecs"

As far as I know clojure.java.io/input-stream uses BufferedInputStream and clojure.java.io/reader uses BufferedReader so there no reason to so dramatical difference in speed. Do I miss something?

2
  • 1
    Are you sure your r2 is correct? Didn't you use .readLine there? (testing if the result is falsy instead of comparing it to -1 would indicate it) Commented Mar 16, 2017 at 16:30
  • Yes, r2 is incorrect. Thanks. Commented Mar 17, 2017 at 7:48

1 Answer 1

1

Your test is flawed. Both BufferedReader and BufferedInputStream return -1 at the end of the stream. So, your test for r2 should also be (when-not (= -1 (.read ....

While the below method of testing is not accurate down to very small millisecond levels, it's accurate enough for this test, and a test using the very good criterium benchmark library for clojure yields similar results. Posting the test again more compactly, for easy copy/paste:

(let [testfile "zerofile"]    ; $ dd if=/dev/zero of=zerofile bs=1k count=1k
  (map (fn [func label]
         (println label)
         (dotimes [_ 3]
           (time (with-open [data (func testfile)]
                   (while (not= -1 (.read data)))))))
    [clojure.java.io/input-stream,  clojure.java.io/reader]
    ["Input Stream:" "\nReader:"]))

One result:

Input Stream:
"Elapsed time: 624.01494 msecs"
"Elapsed time: 650.407183 msecs"
"Elapsed time: 627.244097 msecs"

Reader:
"Elapsed time: 706.776733 msecs"
"Elapsed time: 691.887275 msecs"
"Elapsed time: 703.918226 msecs"
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your help, I see now. I'm exit too soon with a reader in my example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.