PlayFrameworkをちょっと触った
PlayFrameworkを触る機会があったので、自分の備忘録がてら書きます 以下の操作はUbuntu上で実行しています
皆さんは知っていると思いますが、PlayFrameworkはScala(と一部Java)で実装されています。よって利用するにはJavaが必要になります。Ubuntuインストール時のオプションにも依りますが、Javaが入っていないこともあるので、まずはJavaをインストールします
PlayFrameworkの最新バージョンは、この記事を書いた時には2.4.2だったので、必要なJDKのバージョンは8でした。よってJDK8を入れます
$ sudo add-apt-repository ppa:webupd8team/java $ sudo apt-get update $ sudo apt-get install oracle-java8-installer $ sudo apt-get install oracle-java8-set-default
次にPlayFramework本体をダウンロードしてきます。今回は本家のサイトからダウンロードしてくる形にしました
$ cd $HOME $ wget "https://downloads.typesafe.com/typesafe-activator/1.3.5/typesafe-activator-1.3.5.zip" $ unzip typesafe-activator-1.3.5.zip
実行ファイルに対してパスが通っていないので、環境変数に追記
export PATH=/home/ユーザー名/activator-dist-1.3.5/activator:$PATH
動作チェックを兼ねて、以下のコマンドで新規にPlayアプリケーションを作成します
$ activator new SampleApp
するとSampleApp
というフォルダが出来たと思うの、移動して、以下のコマンドで実行します。初回起動はBuildが走るため、ちょっと時間がかかります
$ activator run
ブラウザからlocalhots:9000
にアクセスして、Your new application is readyと表示されれば正常に稼働しています
雑記
いやー全然書いてねえなw
帰省している間はほとんどパソコンを開かなかったので、結局何も進みませんでしたとさ。まあ休みに行っているからそれでいいんだけど
OpenMPで並列化しようとしてうまく行かなかったりRubyの並列処理書き途中だったりして、色々と中途半端だったのですが、それよりも自分の部屋が最悪に汚くなって、完全に作業効率落ちていたので、今日はちょっと重めに掃除しました(大掃除ではないけど、いつもの掃除機かけるだけよりは上な感じで)
まずたくさん積まれた酒瓶を片付け、ビールの空き缶を片付け、ミネラルウォーターのペットボトルを捨てたらエライ綺麗になりました。つーかこまめに捨てよろって話ですね。すみません
さらにもう使わないであろう教科書やプリント類を捨てたり、ダンボールにまとめたら山みたいなのが消失しました。もっと早くにやればよかった。。。
僕の部屋はまだまだものが多いのですが、まあ少しずつ捨てるなり譲るなりしないとなと思っています。どうせ来年には引っ越すわけだし
というわけで久しぶりの更新でした
雑記
だれかNginxのリバースプロキシの設定教えてくれー。うごかんー
さて本当は色々書きたいことあるんだけど、記事にするにはまだ調査不足だし中途半端だしのネタを箇条書きにしてある(だけ)のエントリーだよ(ぉ
- GIL(Global Intterspreter Lock)について色々な言語の対応状況まとめる
- Cocos2dやりだしたし、せっかくならC++をもっとやりこもう。最近のC++すごいモダンだし(小並感)
- HUGOのテーマ作る
- サーバーサイドJavaScriptと真剣に向き合う
- 無線LANルーター壊れかけたので、新しいの欲しい
- PHPバージョン7ってなんぞや5.6(最新の安定版)より2倍早いらしいけど本当??
- CUDA ああCUDA
- 広角の一眼のレンズ欲しい。何がいいかしら
・・・
それにしても暑いですね。僕は完全に夏バテしてしまいました。あと寝不足。あつい 個人的に静的サイトブームなので、ある程度までならCMSいらない感じのHUGOテーマつくろうって思っている(行動しているわけではない)
と言いつつ最近サーバーサイドで書いているのはSinatraですが。。。
GPUのまとめ3
いい加減コードを示していくよw
とりあえずコードを書きます 先にCUDAのドライバーなどがインストールされていること前提で進めています。そのうちインストール方法とかまとめます(ほんとか??)
#include <iostream> #include <malloc.h> #include <helper_cuda.h> # define N (8192 * 8192) # define block_size 196608 # define thread_size 512 __global__ void add( int *a, int *b, int *c) { int thread_id = blockIdx.x * blockDim.x + threadIdx.x; while (thread_id < N) { c[thread_id] = a[thread_id] + b[thread_id]; thread_id += gridDim.x; } } int main(int argc, char** argv) { int *a, *b, *c; ind *dev_a, *dev_b, *dev_c; a = (int*)malloc(N * sizeof(int)); b = (int*)malloc(N * sizeof(int)); c = (int*)malloc(N * sizeof(int)); cudaMalloc((void**)&dev_a, N * sizeof(int)); cudaMalloc((void**)&dev_b, N * sizeof(int)); cudaMalloc((void**)&dev_c, N * sizeof(int)); for (int i = 0; i < N; i++) { a[i] = i; b[i] = 2 * i; } cudaMemcpy(dev_a, a, N * siezeof(int), cudaMemcpyHostToDevice); cudaMemcpy(dev_b, b, N * siezeof(int), cudaMemcpyHostToDevice); add<<<block_size, thread_size>>>(dev_a, deb_b, dev_c); cudamemcpy(c, dev_c, N * sizeof(int), cudaMemcpyDeviceToHost); cudaFree(dev_a); cudaFree(dev_b); cudaFree(dev_c); free(a); free(b); free(c); return 0; }
上から説明していきます。CUDA独自の書き方とかまあ色々説明しなければならないことはあるのですが、まあ適宜最小限の説明で行きます。 最初に色々言われても実際のコード見ないとわからないこと多いもんね
# define N (8192 * 8192) # define block_size 196608 # define thread_size 512
まずここの定数宣言なんだって感じですよね
# define N (8192 * 8192)
今回はCUDAの性能を純粋に測りたかったので単純なベクトル和を計算するのを書いています。
よってこれは計算するベクトルの総和。つまり計算対象は 8192 * 8192
あるってことです
# define block_size 196608
使用するブロック数です。これテキトー(というか、さっきまで使ってたGPUに合わせただけ)なので、適宜変えて大丈夫です。これを変えて処理時間とか見みると結構面白い
define thread_size 512
使用するスレッド数です。これも変えておk
__global__ void add( int *a, int *b, int *c) { int thread_id = blockIdx.x * blockDim.x + threadIdx.x; while (thread_id < N) { c[thread_id] = a[thread_id] + b[thread_id]; thread_id += gridDim.x; } }
これが今回のメインの話題となるやつですね
__global__
ってついたやつはコンパイル時にGPU用のコードとしてコンパイルされます。
もっと正確にいうと、コンパイルはnvcc
というnVIDIAのコンパイラを使うのですが、コンパイルの流れとしては
- コンパイル実行
nvcc -o hoge hoge.cu
- nvccがCPUコードとGPUコードを判別。CPU用はgccに渡し、GPU用はnvccが担当する
- 最後CPU側がGPUバイトコードを呼ぶような感じでリンクして実行ファイル生成(めっちゃ適当)
ってなっていますGPU側はPTXコードというのが生成されたり色々するのですが、
僕があんま詳しくないのでもう少し詳しく取り扱いたいのでまた今度
int thread_id = blockIdx.x * blockDim.x + threadIdx.x;
これがGPUの特徴をよく表していると個人的に思うのですが、並列計算をするときに、SP同士でメモリの参照が狂ったりしないようにそれぞれの順番をuniqになるように定義できるのです。
ちなみに使用するスレッドが1つだけの場合、つまり# define thread_size 1
のときはthreadIdx
はいらなくて良かったりします
以下はとくに変ではない、ふつうのCに登場してくるwhile
文なので説明は省略します。
ではメイン関数をば
int *a, *b, *c; ind *dev_a, *dev_b, *dev_c;
初期化はポインタで指定してね。でないと参照渡しとか出来ないので
cudaMalloc((void**)&dev_a, N * sizeof(int)); cudaMalloc((void**)&dev_b, N * sizeof(int)); cudaMalloc((void**)&dev_c, N * sizeof(int));
これでcuda側のメモリ確保を行います。
for (int i = 0; i < N; i++) { a[i] = i; b[i] = 2 * i; }
ベクトル和の値の初期化をしてるだけです
cudaMemcpy(dev_a, a, N * siezeof(int), cudaMemcpyHostToDevice);
これでCPU側で初期化した配列群をGPU側のグローバルメモリにコピーします
add<<<block_size, thread_size>>>(dev_a, deb_b, dev_c);
ここで先ほどのGPUのコードを呼び出しています。
<<<>>>
で囲まれた部分でこの関数で使用するブロックとスレッドの数を指定できます
cudamemcpy(c, dev_c, N * sizeof(int), cudaMemcpyDeviceToHost);
ここで計算し終わったデータをGPU側からCPU側にコピーしています
cudaFree(dev_a);
みんなだいすきメモリ解放。Cのfree()
のCUDA版です
すげーどんどん説明がテキトーになっているのがわかるかと思われますが、夏バテなので許してください
最後に__global__
の関数、つまりCUDAで処理される関数はvoid型しか取れないのでみなさん注意してください
次回はAWSで実行環境を作る話をしたいです。僕はもうお家帰って寝たいです
最速でAPIをつくろう
写真のフランク・シナトラとは関係ないよ(たぶん)
Androidアプリを書いていて、最初はAPIいらないかと持っていたのですが、今後の実装を考えていくうちにどう考えても辛さしかないわって感じになったので速攻で作りました。
個人的にはAWSのAPI Gatewayとか試したかったんですけど、今回はあまり時間がなかったので。。
(というか日程的にバックエンド開発に時間を割けないorz)
よって一番慣れているもので作りましたとさ
実際にはクローラーが稼働していて、そいつらが読み取ったデーターがMySQLにたまっている感じを想像していただけるとわかると思います。まあ今流行りのクローラーです
とりあえずgem
を入れましょう
gem install sinatra
次にサクッとコードを書きます
例えばDBのテーブルがこんなかんじだったとしまして
create table `hogehoge_items` ( `id` int(10) unsigned not null, `hoge_id` int(10) unsigned not null, `title` varchar(255) not null, `link` varchar(768) not null, `published` varchar(255) not null, `updated` varchar(255) not null, `content` varchar(255) not null, primary key(`id`) ) engine=InnoDB default charset=utf8;
シンタックスハイライトすんじゃん!!びっくり!!
取り乱しました。すみません。出来ないものだとばかり思い込んでいたので。。。
DBスキーマそのまま貼っつけましたが皆さんわかると思うのでこのまま行きます
次に肝心のコードです
require 'active_record' require 'sinatra' db_config = YAML.load_file(File.expand_path(File.join(__FILE__, 'config', 'database.yml'))) ActiveRecord::Base.establish_connection(db_config['db']['production']) set :root, File.expand_path(File.join(__FILE__, '..', 'static')) get '/' do erb :index end get '/news/:hoge_id' do content_type :json, :charset => 'utf-8' entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10) entries.to_json(:root => false) end
本当をいうと今回実装したのと全然構造違うのですが、説明用に変えて書いています。 とりあえず上から説明していきます
require 'active_record' require 'sinatra'
大丈夫ですね。普通にimport
や#include
といった他の言語にもよくあるライブラリの読み込みです
db_config = YAML.load_file(File.expand_path(File.join(__FILE__, 'config', 'database.yml'))) ActiveRecord::Base.establish_connection(db_config['db']['production'])
ActiveRecordを単体で叩けるように設定を読み込んでいます。db_config['db']['production']
部分をproduction
からdevelopment
変えたりすることで開発環境と本番環境を分けたりなど、色々と便利なのですが、とりあえず今回はそこまで凝ったことしなくていいので
あ。ここでdatabase.yml
は既に存在していること前提で話しています(笑)
set :root, File.expand_path(File.join(__FILE__, '..', 'static'))
Sinatraは静的ファイルのディレクトリの場所を変更することが可能です。今回は色々な関係でstaticというフォルダを指定しています
get '/' do erb :index end get '/news/:hoge_id' do content_type :json, :charset => 'utf-8' entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10) entries.to_json(:root => false) end
メインディッシュですね。Sinatraの特徴はMVCアーキテクチャーに則っていないことです。乱暴に言うとCしか持っていません。そしてこれはルーティングを書いているだけです。
ちゃんと設計してあげれば立派なMVCフレームワークになるのですが、ならRails使えよって話で(笑)
ちなみにSinatraをベースにMVCアーキテクチャーを持たせた設計にしてあるのがPadrinoってやつです
僕はいまいちRailsに比べての優位な部分を見いだせていないので使ったことないです。すません
get '/' do erb :index end
これはサイトのトップディレクトリに来たらstatics
フォルダーにあるindex.erb
をrender
する処理を書いています。ちなみにhaml
だろうがslim
だろうが適切なgem
を入れてあげれば対応できます
get '/news/:hoge_id' do content_type :json, :charset => 'utf-8' entries = GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10) entries.to_json(:root => false) end
これはなんかややこしそうですね。しかし分解して読み解けば簡単です
get '/news/:hoge_id' do
でURLに含まれている/news/
以下の文字列を読み取ります。よって
/news/yoshio
というURLに対してアクセスが来た場合、
yoshio
という文字列がsinatra側に渡されることになります
GoogleAlertItems.where(hoge_id: params[:hoge_id]).order('updated DESC').limit(10)
ここで何をしているかというと、URLから読み取った文字列をActiveRecordに渡して、hoge_id
と一致するものを持ってきて更に更新日時が新しい順にし、そして最大10件持ってくるという処理をしています
entries.to_json(:root => false)
説明不要かもですが、みんなだいすきJSONを生成しています。最終的にこいつが結果としてrender
されます
今回はget
しか使っていませんが、もちろんpost
もupdate
もdestroy
も可能です。
長くなったのでここで終わりにしますが、次回はunicornでデーモン化した話を書きたいです
(ちゃんと次回があればの話だがなっ!)
あ。。。GPUの連載止めてた。。書きます