2025/03/20 08:42 One Billion Row Challenge in Racket

ロボ子、One Billion Row Challengeって知ってるか?

はい、博士。大規模なテキストデータ処理のベンチマークですよね。Racketで実装した人がいるみたいですよ。

そうそう!その人が、2023年製の12コアApple M2 Maxで約45秒で完了したらしいのじゃ!

すごいですね!どのように実装したんですか?

複数のplaceに処理を分割したらしいぞ。各placeが入力ファイルを全体を反復処理するんじゃ。

各placeがファイル全体を反復処理するんですか?それだと無駄が多いのでは?

そこがミソじゃ!各placeは、自身のshard番号に一致するエントリのみを処理して、残りをスキップするらしい。

なるほど!シャーディングですね。各placeのwork量を削減できるわけですね。

その通り!データは10MBのチャンクで読み込まれるらしいぞ。

place-localのデータは、location名からstate structへのhashに格納するんですね。state structには、エントリ数、最低気温、最高気温、そのlocationの全気温の合計が含まれていると。

そうじゃ。そして、1つのlocationのデータが複数のplaceに分散している可能性があるから、最終ステップで全placeのデータをlocationごとに結合して、結果を出力するんじゃ。

初期の実装では、main placeがファイル全体をshared-bytesに読み込んでいたんですね。でも、オーバーヘッドが大きすぎたと。

そうなんじゃ。main placeからworker placeに個々のwork unit(行)を送信する方式も、place-channel-putのオーバーヘッドにより失敗したらしい。

hash tableも工夫したみたいですね。通常のRacket hashではなく、独自のopen-addressed hash tableを実装したと。

そう!入力バッファからlocation名をコピーするコストを避けるためじゃ。これにより10-15秒程度の時間短縮になったらしいぞ。

contract checkを無効にするために#%declareを使用したり、racket/unsafe/opsからのimportをrenameしたり、細かいチューニングもしているんですね。

CPUコア2つごとに1つのplaceを生成した方が、コアごとに1つのplaceを使用するよりもパフォーマンスが向上したらしい。place間の同期オーバーヘッドが少ないからじゃろうな。

並列処理の粒度も重要なんですね。勉強になります。

じゃろ?しかし、Racketでこんな大規模なデータ処理ができるとは、驚きじゃな。

そうですね。Racketの新たな可能性を感じます。

ところでロボ子、もし私が10億個のおにぎりを作るチャレンジをしたら、手伝ってくれるか?

10億個ですか!?それはOne Billion Riceball Challengeですね。喜んでお手伝いします!ただし、博士が全部食べるのは禁止ですよ。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。