challenge 分散関数呼び出し

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

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

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

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

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

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

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

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

Posted feedbacks - Scheme

まずは一番乗り狙いで、最もナイーブな実装をば。
エラー処理や効率は考えていません。
eval-remotelyはリモートホストでインタプリタを起動して評価式を送り込みます。

実行例:
gosh> (ref (run-sample "scherzo" 1) 1)
"販売価格 1,600円 (定価2,000円から20%引き)"

ベンチマーク (CPU Pen4 2GHz, メモリ2GB, ループバック使用、Gauche 0.8.11_pre1, ミドルウェア無し)
gosh> (time (run-sample "scherzo" 10000) (values))
;(time (run-sample "scherzo" 10000) (values))
; real   5.247
; user   0.460
; sys    0.130
 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
;; -*- coding: utf-8 -*-
(use gauche.process)
(use srfi-1)

(define (eval-remotely host exprs)
  (let1 p (run-process '(gosh -E "'read-eval-print-loop #f #f #f values'")
                       :host host :input :pipe :output :pipe)
    (unwind-protect
        (map-in-order (lambda (expr)
                      (write expr (process-input p))
                      (newline (process-input p))
                      (read (process-output p)))
                    exprs)
      (begin (close-output-port (process-input p))
             (process-wait p)))))

;; 実行サンプル
(define (run-sample host repeat)
  (eval-remotely host
                 `((define (pricestring 価格 割引率)
                     (format "販売価格 ~:d円 (定価~:d円から~d%引き)"
                            (round->exact (* 価格 (/. (- 100 割引率) 100)))
                            価格 割引率))
                   ,@(make-list repeat '(pricestring 2000 20)))
                 ))

Shiro さんの実装に対抗して速度重視のものを書いてみました。ソケットによって、二つの引数を渡しているだけですが、 RPC ということにしておきます。実験的なコードなので、安全性は考えていません。ソケットを閉じてさえいません。

実行速度はやはり速く、 Celeron 2GHz のマシン(同一)で、 /dev/null  に出力したもので、大体3秒程度でした。実行結果は以下のような感じ。

theo-desktop% cd workspace/doukaku 
theo-desktop% ./rpc-server.scm&
[1] 22494
theo-desktop% ./rpc-client.scm
# 一万行の出力を省略
;(time (dotimes (i *call-times*) (format out "~d ~d\n" (u16vector-ref nv ...
; real  29.516
; user   1.170
; sys    1.100
theo-desktop% 
[1]  + done       ./rpc-server.scm
theo-desktop% ./rpc-server.scm&
[1] 22499
theo-desktop% ./rpc-client.scm>/dev/null 
;(time (dotimes (i *call-times*) (format out "~d ~d\n" (u16vector-ref nv ...
; real   3.434
; user   0.960
; sys    0.840
theo-desktop% 
[1]  + done       ./rpc-server.scm
theo-desktop% 

*サーバとクライアントのCPU・メモリ
  メモリ: 749.1MB
  プロセッサ: Intel Celeron CPU 2.00 GHz

*同一サーバ内での実行か別サーバでの実行か
  同一。

*言語のバージョン
  Gauche scheme interpreter, version 0.8.10 [utf-8,pthreads]

*ミドルウェアを使用している場合,その名前とバージョン
  特にないと思われる。

このプログラムを書くにあたって Gauche (at Lingr) において、びさん、 rui さん、 masa_edw さん、 leque さんらに相談にのっていただきました。どうもありがとう!
 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
;; クライアント
#!/usr/bin/env gosh
(use gauche.net)
(use srfi-27)
(use gauche.uvector)

(define *call-times* 10000)

(define (random-integers size maxnum)
  (let1 v (make-u16vector size)
    (dotimes (i size)
      (u16vector-set! v i (random-integer maxnum)))
    v))

(define (main args)
  (let ((nvec (random-integers *call-times* (expt 2 16)))
	(mvec (random-integers *call-times* 100)))
    (call-with-client-socket
	(make-client-socket 'inet "localhost" 3000)
      (lambda (in out)
	(time 
	 (dotimes (i *call-times*)
	   (format out
		   "~d ~d\n"
		   (u16vector-ref nvec i) (u16vector-ref mvec i))
	   (flush out)
	   (print (read-line in))
	   ))))))

;; サーバー

(let* ((server (make-server-socket 'inet 3000 :reuse-addr? #t))
       (sock (socket-accept server))
       (in (socket-input-port sock :buffering :modest))
       (out (socket-output-port sock)))
  (with-ports
   in out #f
   (lambda ()
     (do ((n (read) (read))
          (m (read) (read)))
         ((or (eof-object? n) (eof-object? m)))
       (format out "販売価格 ~,,',,4:d (定価~,,',,4:d円から~d%引き)"
               (ceiling (*. n (/. (-. 100 m) 100)))
               n m)
       (newline)
       (flush)))))

Index

Feed

Other

Link

Pathtraq

loading...