challenge 分散関数呼び出し

分散関数呼び出しを実装してください.

呼び出される関数は,定価を整数で,割引率(%)を整数で受け取り,
文字列で「販売価格 ○円(定価○円から○%引き)」を返すものとします.
また,数字は3桁のカンマ区切りにするものとします.

たとえば,pricestring(2000, 20) なら
"販売価格 1,600円 (定価2,000円から20%引き)"
を返します.

関数の呼び出し元と,呼び出される側は,物理的に異なる
サーバに配置できることを条件とします.
呼び出し方法は問いませんが,呼び出し方法に名前がある場合,
それをタグに加えてください.
(XML-RPC,SOAP,CORBA,RMI,など)

また,作成した関数を直列に1万回呼び出して,
実行にかかった時間を測定してください.
測定時は別サーバでなくても構いません.
(なるべく別サーバが望ましいです)

測定環境として,
・サーバとクライアントのCPU・メモリ
・同一サーバ内での実行か別サーバでの実行か
・別サーバの場合,通信経路.(100Mbps Ethernet等)
・言語のバージョン
・ミドルウェアを使用している場合,その名前とバージョン
も併記してください.

1つの言語で複数の分散関数呼び出しの実装方法がある場合,
複数の回答を歓迎します.

出題の意図は,様々な分散呼び出し方法の実装例と,
レスポンス速度の確認にあります.
このお題は沢渡 みかげさんの投稿です。 まったく手を加えないでいい完成度の投稿で本当に助かります。 ありがとうございました。

Posted feedbacks - Common Lisp

とりあえず検索して使えそうなコードを探しそれを参考にして切った貼ったで
作りました。
socket自体良く分かっていないため怪しいものができていると思います^^;

できるだけ、処理系非依存にしたかったのですが、サーバ側は、SBCLの、
sb-bsd-socketに依存しているので、残念ながらsbclでしか動きません。
色々探している中で、usocketというものが使えそうだったので、クライアン
ト側は、usocketを使用して作成しました。こちらは、USOCKETがサポートして
いる処理系なら大丈夫だと思います。
USOCKETはASDF-INSTALL可能です。

サーバ: Pentium 1GHz Mem 768MB
クライアント: iBook G4 800MHz Mem 640MB
通信経路: 100Mbps Ethernet
言語: SBCL 1.0.9 (サーバ/クライアント共に)

参考(サーバ)
http://paste.lisp.org/display/1376

測定コード:
 (time 
  (dotimes (i 10000)
   (get-pricestring (random 30000) (random 105) "server" 2000))
   
10,000回実行にかかった時間
-------------------
real: 1202秒
user:   26秒
sys:    11秒

同一マシン(サーバ上)で実行
-------------------
real: 66秒
user: 27秒
sys:  10秒
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
;; ================================================================
;; クライアント
(defpackage doukaku-45 (:use :cl :usocket))
(in-package :doukaku-45)

(defun get-pricestring (price discount% server port)
  (with-client-socket (socket stream server port)
    (format stream "(~D ~D)~%" price discount%)
    (force-output stream)
    (read-line stream)))

;; ================================================================
;; サーバ
;; (ファイルにセーブして、$ sbcl --load server.lisp のように実行し起動させます。
(require :sb-bsd-sockets)
(use-package :sb-bsd-sockets)

(defun return-discount-price (stream price discount%)
  (let ((discount-price (round (* price (/ (- 100 discount%) 100)))))
    (format stream "販売価格 ~:D円(定価~:D円から~D%引き)"
	    discount-price price discount%)))

(defun valid-input-p (input)
  (and (consp input)
       (= 2 (length input))
       (every #'numberp input)
       (every (lambda (x) (<= 0 x)) input)
       (<= 0 (cadr input) 100)))

(defun get-server-socket (hostname port)
  (let ((socket (make-instance 'inet-socket :type :stream :protocol :tcp)))
    (setf (sockopt-reuse-address socket) t)
    (socket-bind socket
		 (host-ent-address (get-host-by-name hostname))
		 port)
    (socket-listen socket 10)
    socket))

(defun get-client-socket (server-socket)
  (socket-accept server-socket))

(defun get-socket-stream (socket)
  (socket-make-stream socket :input t :output t))

(defun close-socket (socket)
  (socket-close socket))

(defun doukaku-45-server (port)
  (let ((socket (get-server-socket "doritos" port)))
    (handler-case
        (progn
          (format t "listening on ~D~%" port)
	  (do* ((client (get-client-socket socket) (get-client-socket socket))
		(stream (get-socket-stream client) (get-socket-stream client)))
	       (())
	    (let ((in (read-from-string (read-line stream))))
	      (if (valid-input-p in)
		  (let ((mesg (apply #'return-discount-price nil in)))
		    (print mesg) (terpri) ;サーバ側確認用
		    (princ mesg stream))
		  (let ((mesg (format nil "~Sは不正な入力形式です。(価格 値引き率(0〜100%))" in)))
		    (print mesg) (terpri) ;サーバ側確認用
		    (princ mesg stream)))
	      (close-socket client))))
      (condition (c) (format t "error occured: ~A~%" c)) )
    (close-socket socket) ))

;; 2000番ポートでサーバ起動
(doukaku-45-server 2000)

Index

Feed

Other

Link

Pathtraq

loading...