Archive for 1月 18th, 2011
1月 18th, 2011 by admin
実行速度計測の記事に対して、MacbookProでやったほうが速かったとの記事がでていたので、原因を考えてみました。
- Pythonのバージョンの違い
このブログでの評価はPython2.5系、処理が速く終わったのはPython2.6系
- OSの違い(MacかWindowsか)
このブログでの評価はWindows7、速かったのは環境はMacOSX 10.6.6
- 演算ビット数の違い
このブログでの評価は64ビットCPUを使っているが演算は32ビット、MacOSX上では64ビットで処理されたかも
Pythonバージョンの違い
諸都合により、今回の計測は「WindowsXP on Core2Duo 3.06GHz(iMac 27′)」で行なっております。
Python2.5
1.14秒かかりました。
1 2 3 4 5 6 7 8 9 10 11
| >>> profile.run('sum(xrange(1,10000001))')
4 function calls in 1.140 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(setprofile)
1 1.140 1.140 1.140 1.140 :0(sum)
1 0.000 0.000 1.140 1.140 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 1.140 1.140 profile:0(sum(xrange(1,10000001))) |
Python2.6
0.918秒かかりました。2割程度速くなっているようです。
1 2 3 4 5 6 7 8 9 10 11
| >>> profile.run('sum(xrange(1,10000001))')
4 function calls in 0.918 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(setprofile)
1 0.918 0.918 0.918 0.918 :0(sum)
1 0.000 0.000 0.918 0.918 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.918 0.918 profile:0(sum(xrange(1,10000001))) |
演算ビット数の違い
自宅の64ビット環境で測定してみました。Corei7 875Xです。OCはしていません。0.834秒でした。64ビットのPythonがインストールされているにもかかわらず、何故かsys.maxintの値は32ビット版の値になっており、長整数型に変換されてしまいました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Python 2.5 (r25:51908, Sep 19 2006, 10:05:36) [MSC v.1400 64 bit (AMD64)] on win
32
>>> import profile
>>> profile.run("sum(xrange(1,10000001))")
4 function calls in 0.834 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(setprofile)
1 0.834 0.834 0.834 0.834 :0(sum)
1 0.000 0.000 0.834 0.834 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.834 0.834 profile:0(sum(xrange(1,10000001)))
>>> import sys
>>> sys.maxint
2147483647 |
Python2.6
0.771秒です。やはりPython2.6のほうが早いようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)] on
win32
>>> import profile
>>> profile.run("sum(xrange(1,10000001))")
4 function calls in 0.771 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(setprofile)
1 0.771 0.771 0.771 0.771 :0(sum)
1 0.000 0.000 0.771 0.771 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.771 0.771 profile:0(sum(xrange(1,10000001)))
>>> import sys
>>> sys.maxint
2147483647 |
まとめ
Python2.6はPython2.5より、1~2割程度高速である。長整数型に変換されているのが処理速度の低下の原因だと思うが、64bit版のPythonを使っているにもかかわらず、何故か64ビット演算されない。WindowsのPythonで、64ビットの整数型が使えないはずはないと思うので、どうやればよいか調べる。なお、「GAE/Python の実行環境を探る」によると、GAE/Pythonでは、整数型は64ビットで扱われているようです。
【追記】
Windows上だと、64ビットPythonでもIntが32ビットになるのは仕様だそうです。
sys.maxint in Python 2.6.1 (amd64) on Windows XP x64
結論
Windows上では、64bit版のPythonを使っていたとしても、int型は32ビットで扱われる。性能測定に使った処理は、32bitには収まらないが、64ビットには収まる値を扱っていたため、Windows上では長整数型、Mac上ではint型での計算となった。長整数型の計算は、int型の計算と比べてコストが大幅に大きいため、Windows環境では大幅に処理時間が伸びてしまった。Pythonのバージョンによる差異もあるが、せいぜい1-2割の差である。よって、演算ビット数の違いが大きな性能につながったのだといえる。
1月 18th, 2011 by admin
リストの基本操作についてまとめてみました。インデックスを指定してpopできる事に気づかない人もおおいのではないでしょうか?
基本操作
Pythonのリストでは以下の4つの基本操作ができます。
1. 末尾に追加
1 2 3 4
| [1, 0, 0, 0, 0]
>>> q.append(2)
>>> q
[1, 0, 0, 0, 0, 2] |
2. 末尾から取り出す
1 2 3 4 5
| [1, 0, 0, 0, 0, 0]
>>> q.pop()
0
>>> q
[1, 0, 0, 0, 0] |
3. 先頭に追加
1 2 3 4
| >>> q = [0,0,0,0,0]
>>> q.insert(0,1)
>>> q
[1, 0, 0, 0, 0, 0] |
4. 先頭から取り出す
1 2 3 4 5
| [1, 0, 0, 0, 0, 2]
>>> q.pop(0)
1
>>> q
[0, 0, 0, 0, 2] |
Stack
操作1と操作2を組み合わせるとStack(スタック)を実現できます。
1 2 3 4 5 6 7
| >>> q = [0,0,0,0,0]
>>> q.append(1)
>>> q.append(2)
>>> q.pop()
2
>>> q.pop()
1 |
Queue
操作1と操作4を組み合わせるとQueue(キュー)を実現できます。
1 2 3 4 5 6 7
| >>> q = []
>>> q.append(1)
>>> q.append(2)
>>> q.pop(0)
1
>>> q.pop(0)
2 |
1月 18th, 2011 by admin
Pythonは、ランタイム環境自体がヘルプ機能を備えているという特徴があります。help()を実行するとヘルプモードが始まります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| >>> help()
Welcome to Python 2.5! This is the online help utility.
If this is your first time using Python, you should definitely check out
the tutorial on the Internet at http://www.python.org/doc/tut/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
return to the interpreter, just type "quit".
To get a list of available modules, keywords, or topics, type "modules",
"keywords", or "topics". Each module also comes with a one-line summary
of what it does; to list the modules whose summaries contain a given word
such as "spam", type "modules spam". |
ヘルプモードでモジュール名を入力すると、そのモジュールについての説明が表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| Help on built-in module math:
NAME
math
FILE
(built-in)
DESCRIPTION
This module is always available. It provides access to the
mathematical functions defined by the C standard.
FUNCTIONS
acos(...)
acos(x)
Return the arc cosine (measured in radians) of x.
asin(...)
asin(x)
Return the arc sine (measured in radians) of x.
atan(...) |
特定のメソッドについての説明だけを表示することもできます。
1 2 3 4 5 6 7
| help> math.sin
Help on built-in function sin in math:
math.sin = sin(...)
sin(x)
Return the sine of x (measured in radians). |
1月 18th, 2011 by admin
Pythonのリストには、popメソッドがあるものの、shiftメソッドがありません。でも、よくpopメソッドの仕様をみてみると、取り出す要素を指定できました。0を指定すれば先頭から取り出せるんですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| >>> q = []
>>> q.append(1)
>>> q.append(2)
>>> q.append(3)
>>> q.pop(0)
1
>>> q.pop(0)
2
>>> q.pop(0)
3
>>> q.pop(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop from empty list
>>> |
1月 18th, 2011 by admin
GAE/Pythonでデータベースを使う場合は、google.appengine.extパッケージのdbモジュールを使います。インスタンス間の関係は、ReferencePropertyを使ってあらわすのが自然なので、連番を振る必要があることはめったにないのですが、昨日公開した、URL短縮サービスでは、連番が必要になりました。しかし、GAEのデータストアには連番を振る機能が用意されていなかったので自作することにしました。
※実は連番の実装がURL短縮サービスで一番苦戦した部分です。
連番生成
連番を作る手順は以下の通りです。
- 過去に作成した最大の番号を取り出す
- 1で取り出した番号より1大きい値を「新しい値」とする
- 2で作成した「新しい値」を保存する
すごく単純な操作なのですが、マルチスレッド環境で確実に動作させるためにはトランザクションを使わないといけません。トランザクションを利用したコードは以下の通りです。1-3までの操作を、prodecureという関数で定義し、それをdb.run_in_transaction()で実行しています。こうすることで、procedure内の操作がトランザクション内で実行されます。
1 2 3 4 5 6 7 8 9 10 11 12
| def getNextNum():
def procedure():
num = MAXNUM.get_by_key_name('URL')
if num is None:
num = MAXNUM(key_name = 'URL')
num.max_num = num.max_num + 1
num.put()
return num.max_num
return db.run_in_transaction(procedure)
class MAXNUM(db.Model):
max_num = db.IntegerProperty(default = 0) |
|
|