スキップしてメイン コンテンツに移動

[Python][Google App Engine]Backendsで無限ループ実装

先日のGoogle App Engine SDK 1.5のリリースで処理時間に制限のないBackendsがリリースされ、さらにこれまで処理で利用したCPU時間に対して課金される仕組みが今後Instanceの起動(アサイン)時間に対して課金されるようになることが発表されました。

つまり、Instanceが1時間起動している間に100回リクエストを捌こうと10回捌こうと金額は変わらないということです。

従来であれば、cronでの最小間隔である1分間に1回処理を実行すると最初の数秒はCPU時間を消費して処理を実行して、残りの40~50秒は何もしない、イコール課金されないという方が理にかなっていました。

しかし、Instance時間になるとたとえ40~50秒間処理を行わなてもInstanceが起動されている間は常に課金されてしまいます。
そうなると、いかにCPUが働いていない40~50秒間を有効に使うか、ということが問題になります。

そこで考えたのが、無限ループです。
特定の処理を無限にループする事によって、Instanceの起動時間全てをループ内の処理に割り当てることができ、Instance時間を有効に活用することができます。

あいにく、まだInstance時間は通常のスケールするInstanceに対しては適用されませんが、BackendsではInstance時間でのQuotaの計算がされています。

将来的な変化に慣れるためにもちょっと実装してみました。

今回ははじめてFlaskというフレームワークを使って書いてみました。

これです。
==========ここから==========
@app.route('/')
def put_queue():
    taskqueue.add(url=url_for('work'),target='test')
    return 'Done'

@app.route('/work',methods=['POST'])
def work():
    for var in range(3600):
        now = datetime.datetime.now() + datetime.timedelta(hours=9)
        str_now = datetime.datetime.strftime(now,'%Y%m%d%H%M%S')
        logging.info(str_now)
        key = 'SPOTS:'+str_now
        logging.info(key)
        rate = GetCurrentRate()
        logging.info(str(rate))
        SPOTS(key_name=key
              ,update=now
              ,USDJPY = rate['USDJPY']
              ,EURJPY = rate['EURJPY']
              ,EURUSD = rate['EURUSD']
              ,AUDJPY = rate['AUDJPY']
              ,GBPJPY = rate['GBPJPY']
              ,NZDJPY = rate['NZDJPY']
              ,CADJPY = rate['CADJPY']
              ,CHFJPY = rate['CHFJPY']
              ,HKDJPY = rate['HKDJPY']
              ,GBPUSD = rate['GBPUSD']
              ,USDCHF = rate['USDCHF']
              ,ZARJPY = rate['ZARJPY']).put_with_cache(key_name=key)
        time.sleep(0.7)
    return 'Done'
==========ここまで==========

簡単なもんです。
まず、通常のcronでput_queue()を叩きます。
次にBackends側でTaskQueueのTaskを受け取り(POST)、3600回繰り返し実行します。

ループの中では為替レートの取得、DataStoreへのput()を行っています。

ログで見る限り、DataStoreへのput()にかかるCPU時間が400~600ms程度。
そこにtime.sleep(0.7)で0.7秒=700msの待ちを加えて約1000~1300ms間隔で実行します。

DataStoreを見るとループ1回で実質1.1秒程度かかっていて、ちょうど1秒間隔の為替レートが取得できています。

上記実行回数(3600回)を考えればもうお分かりのように、1時間に1回cronでput_queue()を叩いてやるように設定してやるだけです。

これでBackendsでの無限ループ処理を簡単に実装できますね。

コメント

このブログの人気の投稿

[Mac]Time Machineのバックアップ先をWindows共有フォルダに設定する

こんばんは。もっくんです。 2台あったWindowsのデスクトップを1台にまとめるついでに、ずっと放置していたMacのバックアップ環境を構築してみました。Finderでコピペするだけでいいんですが、どうせなら「Mac全体を自動的にバックアップします。」という謳い文句のTime Machineを使いたい。 Apple純正のTime CapsuleやUSBの外付けHDDという手もあったんですが、ノートの機動性を落としたくなかったし、なによりタダでできそうなWindows共有フォルダにネットワーク越しにバックアップする方法を取ることにしました。 実際の流れは下記のようになります。 ネットワーク共有フォルダを作成する 空のディスクイメージを作成する ネットワーク共有フォルダにディスクイメージをコピーする ネットワーク共有フォルダのディスクイメージをマウントする マウントしたディスクイメージをTime Machineのバックアップ先に指定する 1.ネットワーク共有フォルダを作成する この手順はそこまで面倒ではないので、簡単な手順だけ。 Windows全体の設定でファイル共有を有効にする(Windowsで作業) Macと共有(Macから見えるように)したいフォルダを作成する(Windowsで作業) 共有したいフォルダに共有設定をする(Windowsで作業) 共有フォルダに接続(Macで作業) 詳細はこちらの記事が画像付きでわかりやすい。 http://blog.goo.ne.jp/beosound/e/7d6d0d0a8f76035f880001eda06c4247 2.空のディスクイメージを作成する いわばこのディスクイメージがバックアップ先のHDDの代わりとなる。 アプリケーション > ユーティリティ > ディスクユーティリティを起動 画面上部の ファイル > 新規 > 空のディスクイメージをクリック 設定画面の各欄は以下のように設定 名前: TimeMachineVolume(なんでもよい) 保存先: デスクトップ(ローカルのわかりやすい場所) ボリューム名: TimeMachineVolume(なんでもよい) ボリュームサイズ: カスタム

[Python]個別銘柄の時系列データをGoogle Financeから取得するプログラム

今日書いたのはこれ。 Google Finance から証券コードを指定して日別の価格情報を取得するプログラムです。 米国市場に上場している銘柄であればCSVでダウンロードでますが、日本の銘柄はできなかったので作りました。 多くの人はYahoo!Japanから取得しているようなので、あえてGoogle Financeから取得してみました。 ちなみに使えるのは東証に上場している銘柄のみです。(おそらく) このプログラムと 日経225構成銘柄一覧取得プログラム を組み合わせれば、日経225構成銘柄の時系列データが取得できてしまいます。 #!/usr/local/bin/python # -*- coding:utf-8 -*- from BeautifulSoup import BeautifulSoup import urllib2,re,datetime,sys class googleFinance2CSV(object): def __init__(self,ticker): ''' 引数で渡されたticker(=証券コード)の時系列データを Google Financeから取得してCSV形式で保持する CSVの列は'Date','Open','High','Low','Close','Volume' ''' self.ticker = ticker self.url = 'http://www.google.com/finance/historical?q=%s&num=200' % str(self.ticker) self.csv = str() soup = BeautifulSoup(urllib2.urlopen(self.url)) tablesoup = soup.find("table", {"class":"gf-table historical_price"}) for trsoup in tablesoup.findAll("tr&qu

[Python]redis-pyでRedis Pub/Sub実装

前から面白そうと思っていたRedisのPub/Sub機能。 redis-pyでどう実装すれば使えるか確認してみた。 ■Pub/Subについて http://ja.wikipedia.org/wiki/出版-購読型モデル ■pub.py from redis import StrictRedis def publish(channel,msg): """ redis-pyにはPUBLISHするためのメソッドがないので、 Redisのコマンドをそのまま実行する為のクラスを使う。 """ sr=StrictRedis() """ 第1引数にRedisのコマンド、第2引数以降は そのコマンドの引数をそのままセット """ sr.execute_command("PUBLISH",channel,msg) if __name__=="__main__": # チャネル"hoge"に"Hello"というメッセージを出版(Publish) publish("hoge","Hello") ■sub.py from redis import Redis def listen(channel): r=Redis() ps=r.pubsub() ps.subscribe(channel) while True: for i in ps.listen(): print i["data"] if __name__=="__main__": # チャネル"hoge"を購読(Subscribe) listen("hoge") ■実行方法・実行結果 (ターミナル1-準備) [user@localhost ~]# python sub.py 1 # => チャネ