pythonでthreadingとmultiprocessing

Python vs Clojure – Evolving « Best in Classをみてて、「ほう」となったので、手元のmacbookで。

t_seq.py

def count(n):
    while n > 0: n -= 1

count(100000000)
count(100000000)

t_thread.py

from threading import Thread

def count(n):
    while n > 0: n -= 1

t1 = Thread(target=count,args=(100000000,))
t1.start()
t2 = Thread(target=count,args=(100000000,))
t2.start()
t1.join()
t2.join()

t_mprocessing.py

from  multiprocessing import Process

def count(n):
    while n > 0:
        n -= 1

t1 = Process(target=count,args=(100000000,))
t1.start()
t2 = Process(target=count,args=(100000000,))
t2.start()
t1.join()
t2.join()

結果

$ time python t_seq.py;time python t_thread.py;time python t_mprocessing.py

real    0m17.032s
user    0m16.886s
sys 0m0.067s

real    0m37.139s
user    0m29.756s
sys 0m23.039s

real    0m8.777s
user    0m16.973s
sys 0m0.083s

Clojureのほう

user=> (defn countdown [n] (when (pos? n) (recur (dec n))))

#'user/countdown
user=> user=> (time (doall (pmap countdown (repeat 2 100000000))))
"Elapsed time: 8164.085 msecs"
(nil nil)

ClojureとScala

説明だけみるとPro Scalaのほうが面白そうな気がするが両方とも欲しい気分

ProductName Practical Clojure (Expert's Voice in Open Source)
Luke Vanderhart
Apress / 4308円 ( 2010-05-17 )


ProductName Pro Scala: Monadic Design Patterns for the Web
Gregory Meredith
Apress / ?円 ( 2011-07-30 )


Programming Clojure chapter 6-9

駆け足で。

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

Chapter 6 (Concurrency)

STMを使う。STMはデータベースでいうACIDのうちACIを提供する。実際にいくつか書いてみないと理解できない感じ。

Chapter 7 (Macros)

マクロ

Chapter 8 (Multimethods)

マルチメソッドの話。

Chapter 9 (Cloure in the Wild)

以下の事柄に関して簡単に説明 - tet-isを使ったユニットテストについて - データベースアクセス - Compojureというweb application framework

章の最後にLancetっていうRakeみたいなソフトウェアでの実例で説明してるんだけど、Lancet使ったことないのでイメージが掴みにくかった。

もう少しClojure触ってから再度読み直すとよいかもしれん。

Programming Clojure chapter 5

どんどん読む。5章はfunctional programmingに関して。遅延評価についてもふれている。

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

clojureは(jvmが?)末尾最適化しないので、tail recursionでなくself recursionをすべし。

self recursionはrecurを使う。またはlazy-seqをつかって遅延評価させる。

mutual recursionの場合はtrampolineという最適化テクニックを使うとよいらしい(未消化)。

Programming Clojure chapter 4

4章はsequenceという抽象の話がメイン。

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

clojureではsequenceの操作関数は重要。若干関数リファレンスみたいになってしまっている部分もあるが、それは仕方ない。どうせ、実際にコード書くときに何度も見返すことになるので、lispとか触ったことがあれば軽く読み流せる章。

Programming Clojure chapter 3

3章はJava周りと最適化の話

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

Syntactic Sugar

javaのメソッドを呼ぶための使いやすい構文糖衣が用意されている/(slash)と.(dot)が重要

Collection

ClojureのCollectionはconcurrency-safeらしい。

Lancet

Clojureのビルドツール。これは使ってみないと読んだだけではよくわからん。

たらい回し関数

jrubyのたらい回し関数のエントリみてたらClojureでもやってみたくなった。

Clojure 1.0.0-
user=> (defn tak [x y z] 
      (if (>= y x) 
      z 
      (tak (tak (- x 1) y z) (tak (- y 1) z x) (tak (- z 1) x y))))
#'user/tak
user=> (time (dotimes [_ 100] (tak 24 16 8)))
"Elapsed time: 27580.504 msecs"
nil

ついでにOCamlでも

let rec tak x y z =
  if y >= x then z
  else tak (tak (x-1) y z) (tak (y-1) z x) (tak (z-1) x y)
;;

for a = 1 to 100 do
  ignore(tak 24 16 8)
done
;;

まずはバイトコードで。

$ ocamlc tak.ml -o tak.exe
$ time ./tak.exe 

real    0m10.777s
user    0m10.692s
sys     0m0.033s

ネイティブコードにコンパイルすると

$ ocamlopt tak.ml -o tak_opt.exe
$time ./tak_opt.exe 

real    0m1.130s
user    0m1.119s
sys     0m0.006s

結構はやい。

そういえばMooseでLispはたらい回し関数はしるくらいまではやっとこうと思いつつ止まってしまっていたのに今気づいた。

Programming Clojure chapter 2

2章はClojureの基本的な説明。

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

キーワードは関数として使える。

user=> (defstruct book :title :author)
#'user/book
user=> (def b (struct book "Programming Clojure" "Stuart Halloway"))
#'user/b
user=> (b :title)
"Programming Clojure"

これは以下のようにキーワードが先にきても良い。

user=> (:title b)
"Programming Clojure"

namespacesの変更

(in-ns name)

meta-data

^が使える。

user=> ^#'str
{:ns #<Namespace clojure.core>, :name str, :file "clojure/core.clj",
 :line 322, :arglists ([] [x] [x & ys]), :tag java.lang.String,
 :doc "With no args, returns the empty string. With one arg x, 
 returns\n  x.toString().  (str nil) returns the empty string.
 With more than\n  one arg, returns the concatenation of the str 
 values of the args."}

clojureでフィボナッチ

遅延評価つかうとこんなに簡単

(def fibs (lazy-cat [0 1]   (map + fibs (rest fibs))))

みてみる

user=> (take 20 fibs)
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)

Programming Clojure chapter 1

導入

ProductName Programming Clojure (Pragmatic Programmers)
Stuart Halloway
Pragmatic Bookshelf / ¥ 3,198 ()
在庫あり。

定番の

user=> (defn hello [name] (str "Hello, " name))
#'user/hello
user=> (hello "kzfm")
"Hello, kzfm"
user=> (hello "clojure")
"Hello, clojure"
user=> (str *1 " and " *2)
"Hello, clojure and Hello, kzfm"

エラーが出たときにstacktrace

user=> (/ 1 0)
java.lang.ArithmeticException: Divide by zero (NO_SOURCE_FILE:0)
user=> (.printStackTrace *e)
java.lang.ArithmeticException: Divide by zero (NO_SOURCE_FILE:0)
    at clojure.lang.Compiler.eval(Compiler.java:4543)
        at clojure.core$eval__3990.invoke(core.clj:1728)
    at clojure.main$repl__5813$read_eval_print__5825.invoke(main.clj:176)
    at clojure.main$repl__5813.doInvoke(main.clj:193)
    at clojure.lang.RestFn.invoke(RestFn.java:426)
    at clojure.main$repl_opt__5853.invoke(main.clj:247)
    at clojure.main$legacy_repl__5878.invoke(main.clj:288)
    at clojure.lang.Var.invoke(Var.java:346)
    at clojure.main.legacy_repl(main.java:29)
    at clojure.lang.Repl.main(Repl.java:20)
Caused by: java.lang.ArithmeticException: Divide by zero
    at clojure.lang.Numbers.divide(Numbers.java:138)
    at user$eval__16.invoke(NO_SOURCE_FILE:6)
    at clojure.lang.Compiler.eval(Compiler.java:4532)
    ... 9 more
nil

requireでなくてuseを使うのはpythonでいうimport some_moduleでなくて from some_module import * をしている感じ

lancetっていうビルドシステムも用意されている(RubyのRakeみたいなもの?)