気がついたら放置すぎた
気がついたらもう今年も終わろうとしているので、
そろそろ本気出す。
Boost.勉強会#4で「ゲーム開発のC++」を話してきました
とりま、
アップロードしました。
スタッフの皆さん、参加者の皆さんお疲れ様でした。
アキラさんには直前まで資料作っていてご心配をおかけいたしました。orz...
MBAほしいわー
我ながら、
MacBook Air 11インチ欲しい!
とかの更新しかしないとかどうかと思う。
使いもしないのにC++のtemplateを毛嫌いする全ての人に
C++AdventCalendarの記事です。
さて、
生配列使ってますか?
tr1::array(boost::array)
使ってますか?
生配列使っていると答えた貴方、
→まず死ね。
はい、arrayが常識ですよね。
さて、とはいえ、
「テンプレートを使うと遅いしコードがでかいし」
「生配列が一番速いしコードが小さいし」
「なのでテンプレート禁止」
なんて話を聞くこともあるかと思いますが、
こういう事をいう人は大抵「テンプレートを書いたことがない」のに言ってます。
なぜか?
こういう人が本当に心配しているのは「テンプレートが肥大化すること」じゃないのです。
「テンプレートが書けないし読めないのを認めたくないからです」
多くはCの老害だからですが、そういう人は放っておいてC++な人はきちんとテンプレートを使いましょう。
だって多くのテンプレートのコードは大きくもなければ非効率でもないからです。
その上、デバッグ用のチェックコードも仕込まれてますし、
ちょっとしたことから大きなことまで様々なところで便利です。
とはいえ実際にアセンブリを見たことがありますか?
じゃ、やってみましょう。
gcc を使って-O5でのコードを比較します。
(Mac上でg++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)を使用しています)
gccでは-Sをつけることでアセンブリコードを吐いてくれるので非常に比較が楽です。
g++ -Wall -S -O5 main.cpp
でやってみました。
enum { DATA_SIZE = 10000000, }; int data[DATA_SIZE]; int hoge() { for (int i = 0; i < DATA_SIZE; ++i) { data[i] = rand(); } return data[0]; }
と、
typedef tr1::array<int, DATA_SIZE> FooArray; typedef FooArray::iterator FooArrayIt; FooArray data2; int hoge() { for (FooArrayIt it = data2.begin(); it != data2.end(); ++it) { *it = rand(); } return data2[0]; }
で比べてみましょう。
生配列は、
LFB1530: pushq %rbp LCFI6: movq %rsp, %rbp LCFI7: pushq %r12 LCFI8: pushq %rbx LCFI9: leaq _data(%rip), %rbx leaq 40000000(%rbx), %r12 .align 4,0x90 L11: call _rand movl %eax, (%rbx) addq $4, %rbx cmpq %r12, %rbx jne L11 movl _data(%rip), %eax popq %rbx popq %r12 leave ret
テンプレートでは、
LFB1531: pushq %rbp LCFI2: movq %rsp, %rbp LCFI3: pushq %r12 LCFI4: pushq %rbx LCFI5: leaq _data2(%rip), %rbx leaq 40000000(%rbx), %r12 .align 4,0x90 L4: call _rand movl %eax, (%rbx) addq $4, %rbx cmpq %r12, %rbx jne L4 movl _data2(%rip), %eax popq %rbx popq %r12 leave ret
完全に一致!
と、最適化をかけるとちゃんと一致します。(かけないと一致しません)
多くのコンパイラではテンプレートコードの最適化はかなり賢く完全に一致します。
ではタプルでは?
typedef tr1::tuple<int, int, int> TripleInt; TripleInt moo() { TripleInt t; tr1::get<0>(t) = 1; tr1::get<1>(t) = 2; tr1::get<2>(t) = 3; return t; }
と
typedef struct StructTripleInt { int one; int two; int three; }; StructTripleInt noo() { StructTripleInt t; t.one = 1; t.two = 2; t.three = 3; return t; }
これも、
LFB3381: pushq %rbp LCFI2: movq %rsp, %rbp LCFI3: movl $1, (%rdi) movl $2, 4(%rdi) movl $3, 8(%rdi) movq %rdi, %rax leave ret
と、
LFB3382: pushq %rbp LCFI4: movq %rsp, %rbp LCFI5: movl $2, -12(%rbp) movl $1, -16(%rbp) movq -16(%rbp), %rax movl $3, %edx leave ret
になり、殆ど変わらないコードになります。
コンパイラにもよりますが、最近のコンパイラは頭良いのでこの辺りは心配ないと思います。
こういった「最適化されたときにゼロコストになるテンプレート」は思いの外沢山あります。
組み込みなどで.textの肥大が辛い場合「テンプレートを使わない」という選択肢もなくはないですが、
まず「テンプレートを使わない」と決める前にきちんと自分の使っているコンパイラの吐くコードを確かめましょう。
懸念としてコンパイル速度が若干遅くなる懸念はありますが、開発の効率性や保守性を考えた時、
テンプレートを使わない、という選択肢はないと思います。
また空間や速度の効率性に関してはEfficient C++等も参考になります。
Efficient C++パフォーマンスプログラミングテクニック
- 作者: ダブブルカ,デビットメイヒュ,浜田光之,Dov Bulka,David Mayhew,浜田真理
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2000/07
- メディア: 単行本
- 購入: 9人 クリック: 105回
- この商品を含むブログ (31件) を見る
PythonのWebフレームワーク使うなら知っておきたいデコレータ
最近「オワタ\(^o^)/」で有名なDjangoしか触ってないダメ人間です。
こんにちは。
Djangoとかどうでもいいがな、
Webフレームワークとかめんどくさいがな、
という最近なのでDつながりでDecoratorの話をします。
ナウでヤングなPythonistaのホットな話題はGCの参照カウンタ、
ではなくてFlaskとかかもしれないですが、
@app.route("/") def hello(): return "Hello World!"
こいつも多分に漏れずDecoratorを使います。
Djangoでも、
@require_GET
とか
@require_POST
とか使ったり見たことがあるんじゃないかと思います。
で、意外と魔法っぽいデコレータですが、
これっていったいどうなってんの?
って事を知らない人が割といたりします。
「とりあえず指定しろって言われたから指定してますサーセンwww」
という感じ何じゃないでしょうか。
なので、よく使われがち&便利でかつ
「デコレータにした方が良いケースなのにロジック記述になってる」なんてことも多々ありますので、
ヤングなPythonistaに「んなこと知ってんだよ」と言われながらも
デコレータについて書いてみようと思います。
Pythonのデコレータってそもそもシンタックスシュガーなんですが、
簡単に言うと、
・デコレータで指定した関数を受け取り、その関数そのものないしはその関数を呼び出す関数を返す
という用途で使われます。
【関数そのものを返す】場合はデコレータ引数とその関数を何らかに関連づけたい、とかで使いますし、
【関数を呼び出す関数を返す】場合はフック関数として使われることが殆どかと思います。
で、Webフレームワークだとこんな感じ。
オールドタイプなのでDjangoスタイルで。
# -*- coding: utf-8 -*- # デコレータ def require_foo(foo_type): def decorator(func): # func はこの場合 bar (関数オブジェクト) # bar の前にフックする関数をラップしてそれを返すことができる def inner(request, *args, **kwargs): # このデコレータに修飾された関数はこのinnerにラップされる request += foo_type # 適当だが return func(request, *args, **kwargs) return inner return decorator @require_foo('hoge') def bar(request): # Django のviewと思ってね return request if __name__ == '__main__': request = 'Hallo World.' print bar(request) # bar は innerである print bar print bar.func_name
デコレータが引数を必要とするので
def require_foo(foo_type):
が一番外にありますが、引数がいらない場合はこれはいらないです。
http://codepad.org/cRsvoqrt
ここで問題として、
print bar
とすると
とかになります。
print bar.func_name
も
inner
です。(ラップ関数の方をbarに代入しているので当たり前ですが)
これだと困るという場合には、
from functools import wraps
を使ってください。
http://codepad.org/HVjuRZMS
@wraps(func)
をinnerにつけるだけで関数名を正してくれます。
普段適当にデコレータを使うと可読性も下がりますが、
Webフレームワークの場合にはデコレータ自作することも多々ありますし、
@require_POST @require_GET def hoge(request): pass
みたいに重ねることもあるでしょうから、
何が起きているのか憶えておくとお得です!(デコレータチェインの動作とか、一応ね)
Webフレームワークの話じゃねえええ、という文句は次の人に言ってください。
次はとらドラ好きで有名な渋川さんがいいのかなあとか。
(スルーされたので@takanoryで? 未確定)
参考文献。
- 作者: Tarek Ziade,稲田直哉,渋川よしき,清水川貴之,森本哲也
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2010/05/28
- メディア: 大型本
- 購入: 29人 クリック: 691回
- この商品を含むブログ (83件) を見る
Python 2.7 対応mobilejpcodecs
id:perezvonさんが公開されているmobilejpcodecsですが、
内部でC拡張が使われており、
Python2.7から(Python3.0のバックポートで)C拡張の型が変わっているため、
2.7以降では実行できません。
なので、Python2.7対応版を
git://github.com/isoparametric/mobilejpcodecs.git
においてあります。
id:mopemope 指摘により、2.6までの場合と2.7以降の場合でコンパイルされるヘッダが切り替わるようになっています。
単に2.7のヘッダに差し替えてあるだけですが、もし良ければお使いください。逆に過去のバージョンでは通らないためご注意ください。
Python Hack-a-thon 2010.11でDjangoの話をしてきました
日本オラクルさんで行われたPython Hack-a-thon 2010.11でDjangoの話をしてきました。
スタッフの皆さん、参加された皆さんお疲れ様でした!
Python x D jango x AWSで作るソーシャルアプリのお話です。
当日の直前まで資料をつくっていたので、時間配分ができませんでした!orz...
次はもっと頑張ります。
Djangoを使うと何が嬉しいか、というお話がメインです。