本を読む

読書やコンピュータなどに関するメモ

Clojureのhttp.async.clientを試した

 Clojureの半日ハッカソン「Tokyo.clj」に参加して、ClojureのHTTPクライアントライブラリであるhttp.async.clientを初めて試しました。以下、メモまとめ。

背景

 ClojureのHTTPクライアントライブラリは変動が激しいようです。http.agentが外れるとか、clojure-http-clientはドキュメントに「this library is deprecated」と書かれているとか、さて、どれがいいんだろうと悩みます。

 clojure-http-clientのドキュメントには、clj-httpかhttp.async.clientがいいんじゃないか、と書き添えてあったので、この2つが気になっていました。特に私の目的が、複数同時接続なので、非同期リクエストのhttp.async.clientを試してみることにしました。

なにもの

https://github.com/neotyk/http.async.client

 イベント駆動型の非同期HTTPクライアントで、Nettyベースだそうです。サンプルやAPIなどを見るかぎり、TwitterなどのStreaming APIとかに力を入れているような印象です。

まず単純な例

 とりあえず単純な例から。まず、lein newして、project.cljの:dependenciesに追加します。

[http.async.client "0.3.1"]

 src/hoge/core.cljに、ほぼサンプルからコピペで書きます。

(ns hoge.core
  (:require [http.async.client :as client]) )

(defn -main []
  (with-open [client (client/create-client)]
    (let [response (client/GET client "http://www.google.co.jp/")]
       (client/string response))) )

 ドキュメントによると、client/GETではブロックせず、client/stringで内容を見に行くときにブロックするそうです。

 実行してみます。

$ lein deps
$ lein run
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
"<!doctype html><html><head><meta http-equiv=\"content-type\" (以下略)

 無事、コンテンツが表示されました。冒頭にSLF4Jの「ロガーが設定されてないよ」というメッセージが出てますが、ここでは置いておきます。

同時接続を試す準備

 同時接続を試すために、「時間のかかるWebサーバー」をローカルで動かします。とりあえずRingで。

(ns slowserver.core
  (:use [ring.adapter.jetty]) )

(def sleep-sec 5)

(defn app [req]
  (do
    (Thread/sleep (* sleep-sec 1000))
    {:status  200
     :headers {"Content-Type" "text/html"}
     :body    "Hello World from Ring"} ))

(defn -main []
  (run-jetty app {:port 8080}) )

 READMEのサンプルにThread/sleepを入れただけです。

同時接続を試す

 localhostの8080番ポートに10接続かけてみます。src/hoge/core.cljはこんな感じ。

(ns hoge.core
  (:require [http.async.client :as client]) )

(defn string-now [x]
  (do (println (. System (nanoTime)))
      (client/string x) ))

(defn -main []
  (with-open [client (client/create-client)]
    (let [sq (map #(client/GET client %)
                  (repeat 10 "http://localhost:8080/") )]
      (println "Now Loading...")
      (doall (map string-now (doall sq))) )))

 10個の(同じ)URLをmapでclient/GETにかけてから、またmapでclient/stringにかけます。その直前に経過時刻を表示することで、各client/stringが呼ばれる間隔を調べます。

 実行してみます。

$ lein run
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Now Loading...
18216574767690
18221629991057
18221630627241
18221631077019
18221631303585
18221636776904
18221637166409
18221637382289
18221637587832
18221637784994
("Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring" "Hello World from Ring")

 1リクエスト目のclient/stringでブロックしたあとは、2リクエスト目以降はさくっと返ってきています。同時接続しているように見えます。

コールバック版

 非同期リクエストなのでコールバックインターフェイスもあるかと思って探したところ、client-request-streamがコールバックを取るようです。

 同じように試してみます。

(ns hoge.core
  (:require [http.async.client :as client]) )

(defn start-request [client url]
  (let [p (promise)]
    (client/request-stream client :get url
                        (fn [state body]
                          (deliver p (str body))
                          [body :continue] ))
    p ))

(defn deref-now [x]
  (do (println (. System (nanoTime)))
      (deref x) ))

(defn -main []
  (with-open [client (client/create-client)]
    (let [sq (map #(start-request client %)
                  (repeat 10 "http://localhost:8080/") )]
      (println "Now Loading...")
      (doall (map deref-now (doall sq))) )))

 コールバック関数からのやりとりにpromiseを使ってみました。

 実行すると、client/GETのときと同じような動作になります。

 ただ、Content-Length:が0だとうまくいかないとか、ちょっとクセがあるようです。いろいろ調べてみましたが、やはり、名前のようにStreaming APIで使うのに都合がいいように作られているようで、そうでない用途なら素直にclient/GETを使ったほうがよさそうです。

コメント

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://emasaka.blog65.fc2.com/tb.php/956-c2dbe609

 | HOME | 

Categories

Recent Entries

Recent Comments

Recent Trackbacks

Appendix

emasaka

emasaka

フリーター。
連絡先はこのへん

Monthly


FC2Ad