楽天テクノロジーコンファレンス2013
昨日、品川シーサイドの本社で開催された楽天テクノロジーコンファレンスに参加して来た。以前に比べて運営が洗練されてきており、これは経験の賜物と思う。松岡先生のツバメプロジェクトのお話しは感動的であった。戦う姿勢に溢れており聴衆に勇気と刺激を与える。松岡先生にはJobsのようなカリスマを感じる。アワード受賞語のスピーチの結びの句を紹介したい。
20年後、いまのアマゾンの全データセンターが持つ計算パワーが、1枚のタブレットコンピュータに入る。その時に向けて何をすべきか? 一緒に競争しましょう!
会議の公用語は英語である。日本人の話す英語は、一部を除いては稚拙だ。しかしその下手な英語でも頑張っている若者達に刺激を受けた。かつて私が学生時代に通った夜間の英語学校でも、校舎内は日本語禁止で、日本語を話したら千円の罰金というルールだった。授業後に立ち寄った喫茶店でも、日本人どおしで必死に英語で話していたこと思い出す。会議の参加者に混ざる外国人と日本人の参加者が自然に融和している光景を目にして、楽天の社内英語化は着実に定着し成果を上げていることを実感した。
終戦のエンペラー
題材が面白い.歴史に対する興味を喚起してくれる良い映画であった.私は1958年生まれであるが,私の生まれるほんの13年前に,日本がこういう状態であったという事実に驚愕する.連合国による統治はその後7年間続き,日本が主権を回復するのは1952年で,私が生まれたのはその僅か6年後である.だが私の幼少の記憶には戦争や占領時代の面影は全く存在しない.これは何故か?この時代になにがあったのか,もっと歴史を勉強しないといけないと強く強く思う.
ところで,この映画は米国でどのくらいの人に観られたのか興味があったので調べてみた.
2013/8/11現在,過去一年間のランキングでは興行成績は以下のとおり.(http://www.boxofficemojo.com)
順位 | タイトル | 収入 | 館数 | 公開日 | 終了日 |
---|---|---|---|---|---|
154位 | 終戦のエンペラー | 3.3億円 | 311館 | 2013/3/18 | 2013/6/13 |
ちなみに1位は「アイアンマン3」で407億円,4,253館であります.(こちらはまだ上映中なので最終成績でない)
WebSocket URIの謎
疑問
RFC6455ではwebsocketのURIスキームが定められている。これは通常のURIと同じ形式で、たとえばこんな風に記述される。
ws://example.com:3000/foo
ところでWebSocketという言葉の印象から判断すると、これはソケットであるからホストアドレスとポート番号さえ指定すれば、接続先は一意に決まってしまいそうな気がする。そうするとこのURIの最後にくっついているpath部分"/foo"は何に使うのだろうか?
調査
JavaScriptでコードを書いてみる。クライアンからサーバへの接続リクエストはこのようになる。
var ws = new WebSocket("ws://example.com:3000/foo");
この接続リクエストを受けるサーバは、こんな風になる。コードは省略しているが、このWebSocketServerオブジェクトは3000番のポートでlistenしている。
webSocketServer.on('request', function (req) { console.log("Request resource: " + req.resource);
クライアントから接続要求があると、WebSocketServerオブジェクトの requestイベントのハンドラにはWebSocketRequestオブジェクトが渡ってくる。WebSocketRequestのresourceプロパティにクライアントが指定したURIのpath部分が入ってる。HTTPからWebSocketへ昇格するときのHTTPヘッダのやりとりを観察すると以下のようになっている.
クライアントからのリクエスト GET /foo HTTP/1.1 Host: localhost:3000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Sec-WebSocket-Version: 13 Origin: http://localhost:3000 Sec-WebSocket-Key: VSDuTDuniJF2SmiyhVPenA== Connection: keep-alive, Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket サーバからのレスポンス HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 7TcssaQZrihZ2PPVX4P5Yd3sQfI= Origin: http://localhost:3000
結論
クライアントからの接続リクエストのHTTPのハンドシェイクのGETメソッドの引数としてpathが渡っている.つまりWebSocketのサーバーは,これをみていろいろ挙動を変えられるということになる.WebSocketとは,ソケットという名前から(原始的なソケットという)誤った印象を持ってしまいそうだが,メッセージのフレームをちゃんと管理してくれるとか,アプリケーションを作る上で便利な機能がそろっているのであった.
[参考URL]
風立ちぬ
ラストでの「自分のつくった飛行機に乗った人間は誰も帰って来なかった」という台詞が胸に染み入る.技術者は時代に関係なく生きられないものだろうか? という思いが頭をよぎった.時代とは無関係に美しいものを作りたいという願い.これは技術者の身勝手な思いなのだろうか.
長引く不況,震災,右傾化,解決の見通しが立たない原発事故など.この映画で描かれる時代と現代がもつ不安感は見事に重なる.はたして,この国は戦争へ向け歩みを進めるのか.
冒頭の蚊帳と畳の緑色が美しく,機関車の走る姿,飛行機の飛ぶ姿の力強さ,優雅さは名人芸.いままでのジブリのファンタージと同列で比較するのは無理があるが,わたしの中で,この作品は宮崎アニメの頂点となった.
[計算機]CodeIQのピッグデータ問題の回答
CodeIQの結城さんの「《ピッグデータ》に負けないで!」https://codeiq.jp/ace/yuki_hiroshi/q303 に応募した際の回答を貼っておきます.結果,評価5 ベスト・ピッグデータ賞(結果が正しく技術メモも十分な解答)をいただきました.成績の分布は下のとおりだそうです.
評価5: 38
評価3: 0
評価1: 15
合計: 53
このソート方法にはバケットソートという名前がついていることは知りませんでした.現在,私のところへはスカウトは来ていない.:-)
[技術メモ]
209679232 <--これが答え
Date: 2013/5/3
1)答えを求めるのに必要なデータ件数は 100*(2^30)件である.一件あたりのデータサイズは2byteなので,最低でもデータサイズは200Gバイトになる.
2)このデータをソートしなければいけない点を考慮すると,このデータをメモリ上はおろか,外部ファイルに持つのも簡単ではない.したがって別のアプローチを考える.
3)データの値は2byteなので,この値をキーとし,値を発生件数とするHashテーブルを作成して処理を行う.これによりソートを行う必要は無くなくなる.
4)処理を2フェーズに分け,前半のHashテーブルの作成はC(ソースコード1)で行い,結果をCSVファイルに出力する.後半の総和を求める部分はRuby(ソースコード2)で記述する.Cを採用したの高速化のため,Rubyを採用したのは,記述のしやすさが理由である.なおCの処理では,SHA1の呼び出し回数をを減らすため,2重ループにしてある.Cの処理部分は,下記の環境で142分かかった.
5)検証はサンプルデータに対して行っているが,充分という気がしていない.もう少し考える必要がありそうだ.出題者がどのように正解を検証したのか非常に興味がある.
6)問題の理解のため,最初にHaskell(ソースコード3)でプロトタイプを作成した.これはサンプルデータでは動くが,実課題のデータサイズでは遅すぎて使えない.
[使用環境]
MacOS 10.7.5
CPU 2.4Ghz Intel Core 2 Duo
メモリ 4G
gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
[感想]
簡単と思い始めましたが,予想以上に手こずり,2日程ゴールデンウィークをつぶしてしまいました.面白い問題をありがとうございました.
[ソースコード1] #include#include #include #include #define COMMON_DIGEST_FOR_OPENSSL #include #define SHA1 CC_SHA1 #define COUNT 100 * pow(2,30) #define SKIPS pow(2,24) #define DATA_MAX pow(2,16) int64_t data[(uint16_t)DATA_MAX]; int main(){ printf("start\n"); uint64_t i; uint32_t j; int k,k2,value; char sbuf[256]; unsigned char digest[40]; // init data array for(j = 0; j < DATA_MAX; j++){ data[j] = 0; } printf("array init done\n"); i = COUNT; printf("limit:%llu\n",i); for(i = 0;; i+=1){ sprintf(sbuf,"%llu",i); SHA1(sbuf,strlen(sbuf),digest); for(k=0;k<10;k++){ if(COUNT <= (i*10)+k) goto done; value = digest[k*2]*256 + digest[k*2+1]; // printf("%llu: %d\n",i*10+k,value); data[value]+=1; } } done: for(j = 0; j < DATA_MAX; j++){ if (0 < data[j]) printf("%d,%llu\n",j,data[j]); } } [ソースコード2] #!/usr/bin/ruby count = 100*(2**30) skip = 2**24 sum = 0 accum_count = 0 k = 0 while l = gets data = l.chop.split(',') value = data[0].to_i n = data[1].to_i accum_count += n while k < accum_count sum += value puts k.to_s + " add:" + value.to_s k += skip end break if count <= k end puts sum [ソースコード3] import Data.Digest.SHA1 import Codec.Binary.UTF8.String import Numeric import Data.List getdata :: Integer -> Integer getdata index = let divisor = 10 q = div index divisor r = mod index divisor in getdata_2 q r getdata_2 :: Integer -> Integer -> Integer getdata_2 q r = let str = int2hexstring (Data.Digest.SHA1.toInteger $ hash $ encode $ show q) hexarray = string2hexarray str in getdata_3 hexarray r getdata_3 :: [String] -> Integer -> Integer getdata_3 s r = let r2 = fromIntegral(r * 2) n0 = hex(s !! r2) n1 = hex(s !! (r2 + 1)) in (n0 * 256) + n1 getsign :: Integer -> Int -> Integer getsign count skips = let d = sort $ makedata count in calc_sum d skips calc_sum :: [Integer] -> Int -> Integer calc_sum d skips = sum $ calc_sum_filter d skips calc_sum_filter :: [Integer] -> Int -> [Integer] calc_sum_filter d skips = let x = (head d) in if *1 ++ str genzeros:: Integer -> String genzeros 0 = "" genzeros n = "0" ++ (genzeros (n-1)) string2hexarray :: String -> [String] string2hexarray (x1:x2:) = [x1:x2:] string2hexarray (x1:x2:rest) = (x1:x2:[]):(string2hexarray rest) hex :: String -> Integer hex s = read ("0x" ++ s) :: Integer main = do let count = 107374182400 -- count = 100 skips = 16777216 result = makedata count mapM_ (putStrLn . show) result
*1:length d) <= skips) then x:[] else x:calc_sum_filter (drop skips d) skips makedata :: Integer -> [Integer] makedata 1 = [ getdata 0 ] makedata n = getdata(n-1):makedata(n-1) int2hexstring :: Integer -> String int2hexstring n = let str = showHex n "" r = 40 - (Prelude.length str) in if r == 0 then str else (genzeros (fromIntegral r