InfoTalk Summer Workshop 2012(Amazon DynamoDB Hackathon)に行ってきました

InfoTalk Summer Workshop 2012(Amazon DynamoDB Hackathon)に行ってきました。
DynamoDBにさわるのは初めてでしたが、非常に有意義な時間でした。今回はチームに分かれてDynamoDBを使用したアプリを作ったりしました。
このDBの一番の特徴は読み書きのThroughputをコントロール出来る点です。これにより運用コストを低減することが出来ます。
但し、現状はThroughputのダウンが1日1回のみの制限がありますので、注意が必要です。

ハッカソンで作ったものではないですが、DynamoDBがどのように動くのかを確認する為に、
CouchDBに流し込んでいるPythonスクリプトを変更し、DynamoDBに入れ込むようにしてみました。
PythonからDynamoDBを扱う場合は、botoを使用します。なお、本スクリプトを実行前にテーブルは作成済みであることとします。

# -*- coding: utf-8 -*-

import sys
import tweepy
import json
import time
import jsonpickle
from datetime import datetime
import re
import boto

CONSUMER_KEY = 'YOUR CONSUMERKEY'
CONSUMER_SECRET = 'YOUR CONSUMER_SECRET'
ACCESS_TOKEN = 'YOUR ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'YOUR ACCESS_TOKEN_SECRET'

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)

conn = boto.connect_dynamodb()
table = conn.get_table('twitter')
count = 0

class CustomStreamListener(tweepy.StreamListener):

    def on_status(self, status):
        results = {}
        try:
            if re.match(u"[ァ-ヶーぁ-ん]" , status.text): 

                pickled = jsonpickle.encode(status)
                results = json.loads(pickled)
                del results['_api']

                item = table.new_item(
                    hash_key=int(results['id_str']),
                    range_key=20120729,
                    attrs={'user': results['author']['screen_name'],
                           'text': results['text']})

                item.put()
                #print item

        except Exception, e:
            print >> sys.stderr, "Encountered Exception:", e
            pass

    def on_error(self, status_code):
        print >> sys.stderr, "Encountered error with status code:", status_code
        return True

    def on_timeout(self):
        print >> sys.stderr, "Timeout..."
        return True 


streaming_api = tweepy.streaming.Stream(auth, CustomStreamListener(), timeout=60)

try:  # sample(): streaming_api.sample()
    #streaming_api.filter(follow=None, locations=QUERY)
    #streaming_api.filter(follow=None, track=QUERY)
    streaming_api.sample()

except Exception, e:
    print >> sys.stderr, "Error: '%s' '%s'" % (str(datetime.now()), str(e))

finally:
    print >> sys.stderr, "disconnecting..."
    streaming_api.disconnect()

Facebookから友人の投稿写真を取得するPythonスクリプト

プライバシー侵害の研究の一環として、FacebookからFQLを使用して友人の投稿写真を取得するPYthonスクリプトを作りました。取得した写真の取り扱いには注意してください。

https://github.com/shmachid/facebook_mining/blob/master/getPic_from_fb.py

スクリプト実行手順は以下となります。

  1. 下記のサイトにアクセスし、Facebookアプリの登録をする
  2. http://miningthesocialweb.appspot.com/
    全ての権限を与える必要はないが、スクリプトが動かなくなる可能性もあるので注意してください。
    求められた権限はそのまま許可し、不要になったら、Facebookアプリを削除すれば良いです。

  3. 権限を与えたら、query実行ページに遷移する
  4. http://miningthesocialweb.appspot.com/query

  5. ページ遷移時に表示される ACCESS_TOKEN をコピーする
  6. ディレクトリ配下の out/facebook.access_token に3のTOKENを貼り付ける
  7. プログラムを実行する
  8. 自分のコネクション数にもよるが、画像1万枚で4時間ほどかかります。

  9. 処理終了後、ディレクトリ配下に picture/ が出来るので写真を確認する
  10. 一枚ずつ見るのが面倒な場合は、 out/get_picture.html を開いても良です。

ディレクトリ構成は以下のようにします。out/以下にトークン情報を格納します。

[shmachid@hoge:~/fb] $ ls
getPic_from_fb.py  out
[shmachid@hoge:~/fb] $ cd out
[shmachid@hoge:~/fb/out] $ ls
facebook.access_token
# -*- coding: utf-8 -*-

import os
import sys
import json
import urllib
import urllib2
from urllib import urlencode
import webbrowser

class FQL(object):

    ## This class was made by ptwobrussell.
    ## please check original code.
    ## https://github.com/ptwobrussell/Mining-the-Social-Web.git

    ENDPOINT = 'https://api.facebook.com/method/'

    def __init__(self, access_token=None):
        self.access_token = access_token

    def _fetch(cls, url, params=None):
        conn = urllib2.urlopen(url, data=urlencode(params))
        try:
            return json.loads(conn.read())
        finally:
            conn.close()

    def query(self, q):
        if q.strip().startswith('{'):
            return self.multiquery(q)
        else:
            params = dict(query=q, access_token=self.access_token, format='json')
            url = self.ENDPOINT + 'fql.query'
            return self._fetch(url, params=params)

    def multiquery(self, q):
        params = dict(queries=q, access_token=self.access_token, format='json')
        url = self.ENDPOINT + 'fql.multiquery'
        return self._fetch(url, params=params)


if __name__ == '__main__':
    try:
	    ## First, you need to assign facebook application and get access-token.
        ## please get the access token from following web-site and copy&paste to file.
        ## http://miningthesocialweb.appspot.com/
        ACCESS_TOKEN = open('out/facebook.access_token').read()
        if ACCESS_TOKEN == '':
            print >> sys.stderr, "Check your token"
            exit()

        if not os.path.isdir('picture'):
            os.mkdir('picture')

        q = "select target_id from connection where source_id = me() and target_type = 'user'"

    except IOError, e:
        try:
            print >> sys.stderr, "IO Error"
            exit()
        except IndexError, e:
            print >> sys.stderr, "Index Error"
            exit()

    fql = FQL(access_token=ACCESS_TOKEN)

    ## 1. get persons id
    print "get person id start"
    persons = [str(t['target_id']) for t in fql.query(q)]
    print json.dumps(persons, indent=4)


    ## 2. get album id
    print "get album id start"
    cnt = 1
    work = []
    for i in persons:
        u = 'select aid from album where owner = %s' % (i)
        work += fql.query(u)
        print cnt
        cnt += 1

    albums = [str(t['aid']) for t in work]
    print json.dumps(albums, indent=4)


    ## 3. get photo id
    print "get photo id start"
    cnt = 1
    work2 = []
    for al in albums:
        e = 'select object_id from photo where aid = "%s"' % (al)
        work2 += fql.query(e)
        print cnt
        cnt += 1

    photos = [str(t['object_id']) for t in work2]
    while 'error_code' in photos: photos.remove('error_code')
    while 'request_args' in photos: photos.remove('request_args')
    print json.dumps(photos, indent=4)
    print "Abount photo count: %s" % (len(photos))


    ## 4. get photo url
    print "get photo url start"
    cnt = 1
    photo_srcs = []
    N = 30
    for k in range(len(photos) / N + 1):
        r = 'select src, width, height from photo_src where photo_id in (%s)' \
               % (','.join(photos[k * N:(k + 1) * N]))
        photo_srcs += fql.query(r)
        print cnt
        cnt += 1


	## 5. select picture : width=320 only
    print "get photo via urllib start"
    cnt = 1
    photo_src = []
    for photo in photo_srcs:
        if photo['width'] == 320:
            photo_src.append('<img src="' + photo['src'] + '">')
            filename = photo['src'].split('/')

            ## get picture
            try:
                urllib.urlretrieve(photo['src'], os.path.join(os.getcwd(), 'picture', filename[-1]))
            except:
                print >> sys.stderr, "Can't get this  picture '%s'" % (filename[-1])

            print cnt
            cnt += 1 


    ## 6. create HTML
    print "create HTML start"
    OUT = os.path.basename('get_picture.html')
    html = "<html><body>%s</body></html>" % (' '.join(photo_src[0:]))
    f = open(os.path.join(os.getcwd(), 'out', OUT), 'w')
    f.write(html)
    f.close()

    ## if you want to show these pictures in a browser, please execute following  command at your terminal.
    ## `open out/get_picture.html`
    #webbrowser.open('file://' + f.name)

    print "Done!"

MapReduce Views in CouchDB

前回に続いて、MapReduceによるView作成、View実行を確認してみました。
Javascript以外の言語でMapReduceを行う場合は、couchDBのiniファイルに以下のようなイメージで追記します。
正常反映されれば、FutonのView Codeセグメントでlanguageとして使用可能となります。

[query_servers]
python = /usr/bin/couchpy

下記はサンプルとして、tweetのユーザ情報でlocation = ‘Tokyo’であるtweetを出力しています。
また、本サンプルではReduce処理を使用していません。
https://github.com/shmachid/twitter_mining/blob/master/define_view_in_couch.py

# -*- coding: utf-8 -*-

import couchdb
from couchdb.design import ViewDefinition


SERVER_URL = 'YOUR COUCHDB URL'    #ex: http://localhost:5984
DB_USER = 'YOUR USER'
DB_PASSWD = 'YOUR PASSWORD'
DB = 'YOUR DB NAME'

server = couchdb.Server(SERVER_URL)
server.resource.credentials = (DB_USER, DB_PASSWD)


try:
    db = server.create(DB)

except couchdb.http.PreconditionFailed, e:
    db = server[DB]

    def mapper(doc):
        if doc['author']['location'] == "Tokyo":
            yield (doc['id'], doc['text'])

    ## if you need to use reduce function, please remove bellow the comment-tag.
    #def reducer(keys, values, rereduce):
    #    return max(values)

    view = ViewDefinition('index', 'map_location', mapper, language='python')
    #view = ViewDefinition('index', 'map_location', mapper, reducer, language='python')
    view.sync(db)


    records = [(row.key, row.value) for row in db.view('index/map_location')]

    for record in records:
        print record[1]

Viewを作成・更新後、初回実行時にViewの更新処理が走る為、View実行完了まで時間が掛かりました。(対象件数は25万件であった)
データ更新が絶えず入っている状況でViewへアクセスがあった場合は、どのよう挙動となるのかが気になります。
ログは以下のように出力されます。何か良い方法あるのかな、探したけど分からなかった。

[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244494 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244520 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244548 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244579 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244606 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244634 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244664 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244693 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244721 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244747 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244773 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244797 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244821 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244848 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244877 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244903 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244934 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244961 for tweets _design/index
[Sat, 05 May 2012 17:01:30 GMT] [info] [<0.6123.0>] checkpointing view update at seq 244991 for tweets _design/index

Twitter Streaming API to CouchDB with tweepy and jsonpickle

Twitter Streaming API: filter()からCouchDBへ流しこむサンプルスクリプトを作りました。
返ってきたStatus情報等を全て格納しておりテーブルサイズが大きくなりやすいので、適度にフィルタを掛けると良いです。
連休前と連休中で画像共有サービスの利用頻度が変わるのかを確認する為にFilter条件をtwippleで行なったところ、ゴールデンウィーク中は1日で19万件程度tweetされていました。
連休前として2週間程前に収集した際は10万件程でしたので、行楽中は画像共有サービスの利用が増えるようです。
https://github.com/shmachid/twitter_mining/blob/master/stream2couch.py

# -*- coding: utf-8 -*-

import sys
import time
from datetime import datetime
import tweepy
import json
import jsonpickle
import couchdb


if (len(sys.argv) < 2):
    print "Usage: please check your parameter"
    sys.exit()


QUERY = sys.argv[1:]

SERVER_URL = 'YOUR COUCHDB URL'    #ex: http://localhost:5984
DB_USER = 'YOUR USER'
DB_PASSWD = 'YOUR PASSWORD'
DB = 'YOUR DB NAME'

CONSUMER_KEY = 'YOUR CONSUMERKEY'
CONSUMER_SECRET = 'YOUR CONSUMER_SECRET'
ACCESS_TOKEN = 'YOUR ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'YOUR ACCESS_TOKEN_SECRET'

auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)

server = couchdb.Server(SERVER_URL)
server.resource.credentials = (DB_USER, DB_PASSWD)


try:
    db = server.create(DB)

except couchdb.http.PreconditionFailed, e:
    db = server[DB]

class CustomStreamListener(tweepy.StreamListener):

    def on_status(self, status):
        results = {}
        try:
            if status.id_str in db:
                return True

            pickled = jsonpickle.encode(status)
            results = json.loads(pickled)
            del results['_api']

            db[results['id_str']] = results

        except Exception, e:
            print >> sys.stderr, "Encountered Exception:", e
            pass

    def on_error(self, status_code):
        print >> sys.stderr, "Encountered error with status code:", status_code
        return True

    def on_timeout(self):
        print >> sys.stderr, "Timeout..."
        return True 


streaming_api = tweepy.streaming.Stream(auth, CustomStreamListener(), timeout=60)
print >> sys.stderr, 'Filtering parameters: "%s"' % (' '.join(sys.argv[1:]),)

try:  # sample(): streaming_api.sample()
    streaming_api.filter(follow=None, track=QUERY)

except Exception, e:
    print >> sys.stderr, "Error: '%s' '%S'" % (str(datetime.now()), str(e))

finally:
    print >> sys.stderr, "disconnecting..."
    streaming_api.disconnect()

PyConJP 2011に行ってきました

PyConJP 2011に行ってきました。
会場が現在通っている産業技術大学院であった為、会場学生枠で参加させて頂きました。
200人以上の方が参加していたようです。

以下のセッションに参加しました。

  1. Pythonチュートリアル
  2. 今までPythonは「Perl, Python, PHPのベンチマークを計測しました」をする際に初歩的な部分しか扱った事がありませんでした。
    本セッションに参加するにあたり、Pythonチュートリアル 第2版は一通り目を通してから参加したのですが、テンポよく教えて頂き非常に良かったです。

    Python Tutorial

  3. PythonとMongoDBでWeb開発
  4. 個人的にDBが絡んだ話がやはり楽しいなと感じました。

  5. PyQtではじめるGUIプログラミング
  6. PyQtを使用してデスクトップアプリケーションを作ってみましょうというお話でした。
    自社のDeveloper Network BlogでPyQtを使用して、基幹システムの情報を一覧表示するアプリケーションが
    紹介されていたので、サンプルを作ってみようと思います。

  7. Pythonで1万台のiPhoneを管理する
  8. 最近、スマートフォンやタブレットが浸透し、業務で使用する端末を会社が用意するのではなく、
    個人端末を使用するケースが増えています。
    その際にポイントとなるのが、セキュリティであり、本セッションでは自社システムに接続可能な端末を
    サーバ側から効率的に管理するということでした。同様の製品が多く出ているところから、
    MDM(Mobile Device Management)分野は伸びているのだなと感じました。
    なお、Androidに対するPush通知は時々こけるそうで、その点iPhoneの方が機器管理をする上では
    機能的には進んでいるそうです。

  9. Pythonによる日本語自然言語処理
  10. 入門 自然言語処理
    の12章:Pythonによる日本語自然言語処理に沿った解説でした。

10月頭に少しまとまった時間が取れそうなので、何かアプリケーションを作ってみようと思います。


Perl, Python, PHPのベンチマークを計測しました

Perl, Python, PHPのベンチマークを計測しました。

=====
1. 環境 及び シナリオ

  1. 実行環境
  2. 実行環境は以下である。
    Platform: Linux(CentOS 5.6)  @sakura VPS
    Memory: 512 MB
    CPU: 仮想2Core

  3. プログラミング言語
  4. 実行・考察を行うプログラミング言語はLAMP構成として通常扱われるスクリプト言語の以下を使用する。
    ・Perl
    ・Python2.4
    ・PHP5.2

  5. 実施シナリオ
  6. No. 演算 概要
    1 i = i + 1 加算
    2 i = i – 1 減算
    3 i = i * i 乗算
    4 i = i / 3 除算
    5 i = i % 3 剰余
    6 s = “Hello,World!” 文字列代入
    7 i = len(string) 文字列数
    8 s = random() ランダム(指定なし)
    9 s = random(1, 100) ランダム(指定あり)
    10 IF (s = “Hello,World!) 文字列判断
    11 IF (i = 5) 数値判断
    12 IF (i = TRUE) Bool値判断
    13 IF文ネスト 条件分岐ネスト
    14 Switch文 ループ(Switch)
    15 While文 ループ(While)
    16 For文 ループ(For)
    17 Foreach文 ループ(Foreach)
    18 print “Hello, World!” 文字列出力
    19 関数呼び出し 関数
    20 File Open, Close オープン, クローズ
    21 File read 1行毎の読み込み
    22 File Write 1行毎の書き込み

    実行時のループ回数は、10000000回ループさせる。但し、実行に時間の掛かり過ぎるシナリオ等に関しては回数を減らす事とする。例外シナリオは以下である。
    No.17: 100000回 PHPにおいて例外が発生する為。
    No.18: 10000回 標準出力に文字列出力する為、処理
    対象のprint文の計測が行いづらい為。

  7. 実施前考察
  8. 本レポートで実行対象となるプログラミング言語はそれぞれ実績のある言語であり、Webサービス開発においてよく使用されている。私はPerl, PHPの経験はあるがPythonは今回が初めての使用となる。
    Perlは全体的に処理が速く、ファイル操作に長けているイメージがある為、全般的にPerlのパフォーマンスが良いと考えている。
    PHPは全体的に処理が遅いイメージがある。特にrandom()やファイル操作が遅いイメージがある。
    Pythonを使用するのは今回が初めてである為、あまりイメージが出来ないが、処理速度的にはPerlと同様の計測値となると予測する。

    よって、 ほぼ全シナリオでPerl < Python < PHP の順番で処理コストが高くなると考える。

  9. 実施方法
  10. 以下の要領で実施を行う。

    1. プログラミング言語毎に22個のプログラムを作成する。
    2. 実施シナリオ毎のアルゴリズムは同一とする。実行時間計測アルゴリズムに関しては後述する。
    3. 言語によっては命令が存在しないケースがある為、その場合は代替(同等)機能を使用する。No.16のPythonにおけるFor文等。
    4. Perlに関しては、ミリ秒単位を取得する組み込み関数がない為、Time::Hiresモジュールを使用する。
    5. シナリオ毎に10回実行し、実行結果として平均値を記録する。その際のコマンドは以下ように実行する。(以下はPythonでの例)
      # loop=1; while [ $loop -le 10 ]; do loop=`expr $loop + 1`; ./check1.py >> result/check1; done;
    6. eの実行結果から平均値を出力するスクリプトを実行し、平均値を得る。平均値出力スクリプトは以下である。
      ====
      #! /usr/bin/perl
      open(IN, $ARGV[0]);
      while (<IN>) {
      $total += $_;
      $count++;
      }
      close(IN);
      print $total / $count . “n”;
      ====
  11. 実行時間計測方法とサンプルコード
  12. 言語毎の実行時間計測は以下のように行う。

    以下では、各言語のシナリオ1のプログラムである。

    Perl
    ====
    #!/usr/bin/perl
    use Time::HiRes;

    my $starttime = Time::HiRes::time;
    for($i=0; $i<10000000; $i++) {
    }
    my $looptime = Time::HiRes::time – $starttime;
    my $starttime = Time::HiRes::time;

    my $j=0;
    for(my $i=0; $i<10000000; $i++) {
    $j = $j + 1;
    }
    print Time::HiRes::time – $starttime – $looptime . “n”;
    ====

    Python
    ====
    #!/usr/bin/python
    import time

    starttime = time.clock()
    for i in range(10000000):
    pass

    looptime = time.clock() – starttime
    starttime = time.clock()

    j = 0
    for i in range(10000000):
    j = j + 1

    print time.clock() – starttime – looptime
    ====

    PHP
    ====
    <?php
    $starttime = microtime(true);
    for($i = 0; $i<10000000; $i++) {
    }
    $looptime = microtime(true) – $starttime;
    $starttime = microtime(true);

    $j=0;
    for($i=0; $i<10000000; $i++) {
    $j = $j + 1;
    }
    echo microtime(true) – $starttime – $looptime . “n”;
    ?>
    ====

2. 実行

  1. 実行結果
  2. 以下が実行結果である。シナリオ毎に最も良いタイムに橙色にしている。また、特徴的な値となった結果は赤色とし、次項以降で考察を行う。なお、単位は全て”秒”である。

    演算 Perl Python PHP
    i = i + 1 0.8 1.04 0.44
    i = i – 1 0.81 1.13 0.45
    i = i * i 0.82 1.3 0.46
    i = i / 3 0.74 1.56 0.73
    i = i % 3 0.84 1.47 0.5
    s = “Hello,World!” 0.87 0.65 0.93
    i = len(string) 1.12 1.64 1.8
    s = random() 0.22 2.05 1.73
    s = random(1, 100) 0.95 27.65 2.86
    IF (s = “Hello,World!) 0.89 0.51 0.78
    IF (i = 5) 0.94 0.49 0.44
    IF (i = TRUE) 0.97 1.08 0.37
    IF文ネスト 0.60 2.05 1.67
    Switch文 251.03 2.81 2.01
    While文 1.13 1.64 0.77
    For文 0.67 1.18 0.91
    Foreach文 0.02 0.01 0.06
    print “Hello, World!” 1.2 0.47 0.96
    関数呼び出し 1.74 1.52 1.56
    File Open, Close 69.01 61.46 80.04
    File read 2 1.46 3.54
    File Write 2.02 4.94 23.18

3. 考察

実行前の考察では、全てのシナリオでPerlが優位だと考えていたが、結果は異なっていた。
この考察としてはPerlの時間計測用の関数において、ミリ秒単位で計測が出来なかった為、
Time::Hiresモジュールを使用した事が影響している可能性がある。
但し、Perlならではの優位性が示されているシナリオもある為、現状のまま考察を進める事とする。

  1. randint()
  2. Pythonのrandint()が非常に遅い結果となった。Perlと比較すると約27倍の差である。調査したところ、Perl, PHPのrand()は組み込み関数であるのに対し、Pythonのrandint()は標準モジュールでの提供であった。
    また、randint()よりもchoice()を使用した方が速いとの情報があった為、変更し実行計測したところ、
    27.65 → 12.36 と半分以下の実行結果となった。但し、Perl, PHPと比較するとまだ遅い結果であった。
    この事からC等で記述される組み込み関数はやはり速いということが分かった。

  3. switch文
  4. Perlのswitch文が異常な程、遅い結果となった。これはPerlには組み込みでswitch文がない為、標準モジュールのSwitchを使用した事が影響していると考えられる。最速であったPHPと比較するとその差は100倍である。
    3.1のrand()と同様に以下に組み込み機能が速いかを再認識させられた。

  5. File操作
  6. 実行前の考察よりPHPはファイル操作が不得意であると考えていたが、その通りの結果であった。特にfopen(), fclose(), fwrite()のパフォーマンスが悪かった。
    また、ファイル操作はPerlが非常に有利だと考えていたが、Pythonが健闘している。

  7. その他
  8. シナリオ毎の実行結果の色付けを確認すると、PHP列に橙色が多く付いている。PHPは全般的に処理が遅いと考えていたが、結果から見ると異なっていた。以前の経験ではPHPのrandom()は遅いと感じていたが、やはりPerlと比較すると倍以上の差が出ていた。(Pythonとの比較に関しては、3.1を参照の事)

  9. 最後に
  10. それぞれのプログラミング言語には高速化技術が存在する。例えば、Perl: mod_perl, Python: mod_wsgi, PHP: APC, eAcceralator等である。これらの技術を使用すれば、より良いパフォーマンスが出やすいが、その前段階として、言語毎の特徴を押さえた上でプログラミング言語の選択や処理ロジック, アルゴリズムを組んでいく必要がある。

=====

おわりです。