路傍のプログラマ

只のプログラマが綴る愚痴と備忘録

Macを作りたいMSと、Windows互換機を目指すApple

2007-06-29 16:56:00 | Birds-Of-Feather
記事「Microsoft、Office搭載で格安の「IQ PC」をインドで発売へ」
http://journal.mycom.co.jp/news/2007/06/29/015/index.html
より。

とうとうMSはハードウェアもOSもアプリケーションも(接続サービスさえも!)込みのパッケージを販売する気になった模様。

記事「OS X ハッキング! (230) Windows版Safariに秘められた野望」
http://journal.mycom.co.jp/column/osx/230/index.html
より。

「「CoreGraphics.dll」が、すなわちCoreGraphicsがWindowsに移植されていた」

とのことで、これまで、Appleが互換機を作らせないために、かなりの努力を払ってがんじがらめにしていたはずのグラフィックスサブシステムがあっさりWindowsに移植されたらしい。

これで、開発者からしてみれば、Macintelのソフトとは、ちょっと特殊なライブラリを使ってるWindowsソフトである、とも見なせるわけで・・・

どちらもそれなりの皮算用があってのことだろうけど、どんな結果になるんだろう。

Parallel Pythonは~ (その2)

2007-06-26 17:53:53 | プログラミング
調子に乗って、別のPCでもやってみました。

CPUは4コア、メインメモリは2GB、HDDもかなり早いやつです。

結果は、オリジナルが13秒、パラレル版が、ワーカスレッド(というかプロセス)の数を1, 2, 3, 4と変えていくと、それぞれ、7.8秒、5.8秒、5.7秒、6.0秒と変わりました。

こうしてみると、今回のケースではワーカスレッドを3つ以上使うと遅くなってしまうようで。

当たり前の結果とはいえ、きちんと使うには、きちんとしたチューニングが必要そう。

Parallel Pythonは富豪プログラミングの夢を見るか

2007-06-25 21:09:18 | プログラミング
メニーコア時代を見据えて、Pythonで並列プログラミングできるか、少し確かめたくなりました。

いくつか試行錯誤したのですが、結果から言うと、Parallel Pythonというのを使えば割とらくに並列プログラミングできることもあるかもしれない、という感じでした。

お題として使ったプログラムは、指定した拡張子を持つファイルから、指定した文字列を探すというものです。

まず、並列化していないもの。

import sys
import os
import os.path
import time

if __name__ == '__main__':
 if len(sys.argv) == 1:
  print "hoge pat exts..."
  sys.exit(0)
 
 pat = sys.argv[1]
 exts = sys.argv[2:]
 
 t0 = time.time()
 
 for root, dirs, files in os.walk('.'):
  for filename in files:
   for ext in exts:
    if filename.endswith(ext):
     filepath = os.path.join(root, filename)
     f = file(filepath, "r")
     for linenumber, line in enumerate(f):
      if line.find(pat) >= 0:
       print "%s(%d): %s" % (filepath, (linenumber + 1), line.rstrip())
     f.close()
 
 t1 = time.time()
 print "time: %f sec" % (t1 - t0)

つぎに、これをParallel Pythonを使って並列化(マルチプロセス化)したもの。

import sys
import os
import os.path
import time
import pp

def findpat(pat, filepaths):
 for filepath in filepaths:
  f = file(filepath, "r")
  for linenumber, line in enumerate(f):
   if line.find(pat) >= 0:
    print "%s(%d): %s" % (filepath, (linenumber + 1), line.rstrip())
  f.close()

# tuple of all parallel python servers to connect with
ppservers = ()
#ppservers = ("10.0.0.1",)

if __name__ == '__main__':
 if len(sys.argv) == 1:
  print "hoge ncpus pat exts..."
  sys.exit(0)
 
 ncpus = int(sys.argv[1])
 pat = sys.argv[2]
 exts = sys.argv[3:]
 
 t0 = time.time()
 
 job_server = pp.Server(ncpus, ppservers=ppservers)
 #print "Starting pp with", job_server.get_ncpus(), "workers"
 
 filepaths = []
 jobs = []
 for root, dirs, files in os.walk('.'):
  for filename in files:
   for ext in exts:
    if filename.endswith(ext):
     filepath = os.path.join(root, filename)
     filepaths.append(filepath)
     if len(filepaths) > 50:
      jobs.append(job_server.submit(findpat, (pat, filepaths), (), ()))
      filepaths = []
 
 if len(filepaths) > 0:
  jobs.append(job_server.submit(findpat, (pat, filepaths), (), ()))
  filepaths = []

 for job in jobs:
  job()
 
 t1 = time.time()
 print "time: %f sec" % (t1 - t0)

この2つを、手元にある2コアのCPUのPCで、OpenOfficeのソースコードから「long long」という文字列を探すのに使ってみました。何回か繰り返し実行して、平均を取ってみます。

並列化していない上のやつは、18秒くらい。並列化した下のやつは、10秒くらい。ということで、確かにパフォーマンス稼げてます!

ただし、やっぱり純粋に関数型プログラミングにはなりきれてません。

具体的に言うと、最初、ファイルごとにジョブで処理するようなルーチンを書いてみたのですが、全く速くなかったので、ファイルが50個見つかるまで待って、それらに対する処理を1つのジョブにするように書き換えました。

最初のコードで遅くなった原因は多分、ジョブを作るオーバーヘッドが大きいことでしょう。さっさと泥臭いコードに書き換えてしまうところが、私が富豪プログラマになりきれないところですね・・・

意外だったのは、上の例は単純な文字列検索なので、CPUよりファイルI/Oやメモリがボトルネックになっているのではないか?という予想があっさり覆されたこと。

まあC++やJavaで実験すれば結果は違うかもしれませんが・・・そこはそれ、富豪プログラミングということで・・・

ちなみに、Parallel Pythonのサイトはこちらです。
http://www.parallelpython.com/

鬱といわれても

2007-06-19 00:12:36 | その他
いつの間にかトラックバックに「鬱プログラマー転職」の文字が。

世間一般的にはこの時期に鬱になるプログラマが多いのかなあ?と思いつつ、何となくググってみると・・・

Walkin' Around minus さんの投稿のページ
http://iandeth.dyndns.org/mt/ian/archives/000082.html
に、

「昇進(中略)【プログラマ】残業代が出なくなり、収入は減って、仕事ばかり増える。鬱になる。」

とか。思い当たる節あり。

鬱。

マウスってそんなに健康に悪いかなあ

2007-06-18 18:02:05 | その他
記事「勤務先ブラウザ、8割近くがマウスのみで操作」
http://japan.internet.com/research/20070618/1.html
より。

「1時間以上もブラウザをマウスで操作するとなると、長い期間には、手首を傷めたりしないだろうか。キーボードのショートカットを自然に覚える方法はないものだろうか。」

とあるけど、Webブラウザの操作はほとんどマウスだなあ。気が楽だし。キーボードのショートカットを使う必要もあまり感じないし。

Webブラウズで、キーボードの方が手首の健康にいいって本当だろうか。

むしろ、スクロールホイールがずーっと回り続ける、ボタンがたくさんついてる、エルゴノミクスなマウスを導入した方が、健康に良さそうな気がする。

今度試してみよう。

OSXで作ったzipをWinで解凍するさらにもう一つの方法 (Python)

2007-06-14 11:52:12 | プログラミング
Macで作ったzipファイルを解凍しようとするとファイル名が文字化けしてしまいます、みたいな問題が未だに絶えない昨今。

原因は割と単純で、OS Xが作るzipファイルは、ファイル名がutf-8でエンコードされて格納されるのに対して、WindowsはシフトJIS(より正確にはCP932)でエンコードされているからです。

フリーソフトを使った解決策もあるようですが、ここはひとつプログラマ的な解決策として、Pythonでやってみます。

以下の例では、OSXで作ったzipファイル(中身のファイルは「ほげテキスト.html」)をVista上でPythonのインタラクティブシェル(IDLE)で解凍します。

まず、必要なモジュールをインポートしておきます。

>>> import os
>>> import zipfile
>>> import unicodedata

zipファイルがあるディレクトリに移動し、zipファイルの名前を調べます。

>>> os.chdir(r'C:temp')
>>> os.listdir('.')
['mandel.py', 'x82xd9x82xaf_x83ex83Lx83Xx83g_html.zip']

2つめのファイルがOSXで作ったzipファイルです。
このzipファイルを開いて、格納されているファイルの名前を調べます。

>>> zf = zipfile.ZipFile('x82xd9x82xaf_x83ex83Lx83Xx83g_html.zip', 'r')
>>> names = zf.namelist()
>>> print names
['xe3x81xbbxe3x81x91xe3x82x99xe3x83x86xe3x82xadxe3x82xb9xe3x83x88.html']

ここで、ファイル名のエンコーディングを変更するための関数(utf-8を正規化してからシフトJISに直す関数)を定義しておきます。

>>> def decu8(s): return unicodedata.normalize('NFC', unicode(s, 'utf-8')).encode('Shift_JIS')

この関数を使って、格納されているファイルの名前を印字してみます。

>>> print decu8(names[0])
ほげテキスト.html

後は、格納されているファイルのバイト列を取り出して、ファイルに保存すればOKです。

>>> f = file(decu8(names[0]), 'wb')
>>> f.write(zf.read(names[0]))
>>> f.close()

後始末として、zipファイルを閉じておきます。

>>> zf.close()

この辺がささっとできるのは、さすがスクリプト言語ですね。

逆(Win → OSX)も、やってませんが、多分、簡単にできることかと。


ちょいとひねれば、値が変わる、ベンチマークの難しさ (Python)

2007-06-11 00:00:35 | プログラミング
あるページ
http://www.timestretch.com/FractalBenchmark.html
に、いろんなプログラミング言語でマンデルブロ集合を求めるベンチマークがありました。

Pythonはgccより200倍ほど遅いか、ふんふん、と思ってちょっとソースコードをみてみました。

すると、肝心のループのところが、
  while True:
   i += 1
   temp = zr * zi
   zr2 = zr * zr
   zi2 = zi * zi
   zr = zr2 - zi2 + cr
   zi = temp + temp + ci

   if zi2 + zr2 > BAILOUT:
    return i
   if i > MAX_ITERATIONS:
    return 0
と、少し緩めのコードになっています。多分私なら、
  for i in xrange(0, MAX_ITERATIONS):
   zr2 = zr * zr
   zi2 = zi * zi
   zi, zr = zr * zi * 2 + ci, zr2 - zi2 + cr

   if zi2 + zr2 > BAILOUT:
    return i
  return 0
と書くでしょう。

C++やJavaだけやっていた頃の私なら、これくらいの違いなら「まあ賢いコンパイラがよきに計らってくれるから」と気にしないですむのですが、何かと予想外の振る舞いをしてくれるPythonとなるとそうもいきません。

実際、手元のマシンで実行してみると、オリジナル(上のやつ)は、2.07秒、書き換えた方は1.63秒と、かなりの違いが。

いや、Cに比べれば、200倍遅いか160倍遅いかくらいで、五十歩百歩よりもまださが差が小さい、とも言えますけれども。

まあ、スクリプト言語を使っていて、こんなので目くじらたてる方がおかしいのかも知れませんね。頭が固いか。

もう2008ですか~

2007-06-07 12:02:17 | プログラミング
記事「マイクロソフト、「Visual Studio 2008」を発表」
http://www.itmedia.co.jp/enterprise/articles/0706/07/news009.html
より。

もう2008ですか。まだ2003.NETを使ってるんですけど。

Orcasと言ってたときは、「まだまだ先かな~」と気を抜いてたんですが、もうそろそろ調べないと。

個人的には、IronPythonのコードを、ステップ実行できるようになるとうれしいかも。

それにしても、2005は全世界的にスキップなんですね。やっぱりというか。まあ使ってなかったからいいけど。

テレビはバナーになった

2007-06-06 21:09:12 | その他
記事「【NET Marketing Forum】「自分に関係ないメッセージは排除される時代に」--- 資生堂の加藤参事」
http://itpro.nikkeibp.co.jp/article/NEWS/20070606/273839/
より。

「TVはバナーになった」

言い得て妙。

そういわれれば、最近はやりは紹介番組ばかりだし。

売れ筋ランキングや店の紹介はともかく、人が書いた本の中身をなぞる旅行番組やインタビュー番組、テレビ番組を紹介する番組、新聞や雑誌の見出しを出して雑談する番組、果てはインターネットから拾ったネタを都市伝説として紹介する番組もあったり。

たいていは飛ばしながら見るし。

TVつけっぱなしで気が向いたときだけ画面を見るか、あるいは、ハードディスクに録画しておいて、早送り再生+スキップで、放送時間の半分くらいの時間で見るかだし。

後で必要なところは画面に出るURLをたどればいいようになったし。

実感として納得いくところですね。

boost::optionalはループでも便利

2007-06-01 20:59:03 | プログラミング
C++向けライブラリboostにあるboost::optionalは、
値がない状態(初期化すらされていない状態)を表現できる仕組みです。

例題では、
double sqrt(double n );
で、n < 0のときは戻り値がないことを示すために、
boost::optional<double> sqrt(double n);
とする例が挙げられています。

ちなみに、使う側は、(あたかもポインタのように)値があるかをチェックして、その後使う、という風にします。
boost::optional<double> value = sqrt(なにか計算式);
if (value) {
 std::cout << "答え: " << *value << std::endl;
} else {
 std::cout << "解なし" << std::endl;
}

boost::optionalの例題はネットで見る限り、なぜか関数の戻り値の例ばかりです。
が、実際に使ってみると、なかなかどうして、boost::optionalはちょっとした
ループでも便利に使えることがわかります。

たとえば、繰り返しの直前の値を保持する例。

template<typename IterT, typename ValueT>
void print_unique_values_in_sorted_sequence(IterT begin, IterrT end)
{
 boost::optional<ValueT> lastValue;
 for (IteratorType i = begin; i != end; ++i) {
  if (! (lastValue && *i == *lastValue))
   std::cout << *i << std::endl;
  lastValue = *i;
 }
}

あるいは、条件を満たすものが見つかったときに、その値を保持する例。

boost::optional<size_t> smallGapIndex;
boost::optional<size_t> largeGapIndex;
for (size_t i = 0; i + 1 < ary.size(); ++i) {
 double diff = fabs(ary[i + 1] - ary[i]);
 if (! smallGapIndex && diff < 0.0001)
  smallGapIndex = i;
 if (! largeGapIndex && diff > 1000.0)
  largeGapIndex = i;
 if (smallGapIndex && largeGapIndex)
  break; // for i
}
if (smallGapIndex)
 std::cout << "small gap index = " << *smallGapIndex << std::endl;
if (largeGapIndex)
 std::cout << "large gap index = " << *largeGapIndex << std::endl;

公開するAPIにboostの文字を入れるのは禁止されているときでも、
こういうこそっとした使い方ならお目こぼしになる可能性もありますし。
おすすめです。

(最初、boost::optionalの実装って、本当はポインタを持ってヒープを
割り当ててるんじゃないかと疑いつつ、optional.hppを見たのですが、
いやもう、とても鍛えられたコードでした。疑ってごめんなさい)