Skip to content

Instantly share code, notes, and snippets.

@u1tnk
Created February 28, 2013 01:51
Show Gist options
  • Save u1tnk/5053543 to your computer and use it in GitHub Desktop.
Save u1tnk/5053543 to your computer and use it in GitHub Desktop.

Ending

Unixのプロセスの動作はabstractionとcommunicationの二つについてだ

Abstraction

kernelはプロセスの抽象的(シンプル)なビューを持つ 私達のようなプログラマは二つの言語の違いをソースコードから見つけるのに慣れている

私達は色んな用途に使うたくさんのプログラムを習得している。 GCを持つようなプログラムでメモリ効率的なプログラムを書く事は不可能だ、Cを使わなければならない、けど、オブジェクトが必要だ。じゃあC++を使おう…

でもカーネルに言わせれば同じようなもんだ。全てはコンパイルされて、最後にはカーネルが読めるような単純なもんになるんだ。 そしてそのレベルでは全てのプロセスが同じように扱われる。 全ては数値のidを取得して、カーネルのリソースへの平等にアクセスできる。

この早口のおしゃべりのポイントはなんだろう? Unixプログラミングならこれらのノブをちょいとひねれるぜ。 それはあなたがプログラムレベルで作業するときにはできない事をする事ができる。

Unixプログラミングはプログラミング言語にとらわれない。 それはあなたのRubyスクリプトとCプログラムのインタフェースをする、 逆も同じ(Vice Varsa) それはあなたにプログラミング言語をまたがる再利用をさせます。 UnixプログラミングスキルスキルでRubyからptyhon,C,node.jsへの連携させられる。 これらはプログラミング一般についてのスキルです。

Communication

新しいプロセスを作る事に加えて、ほとんど全てで話した事は通信に関してだった。 上記の抽象化の原則に従って、カーネルがプロセス間の通信の非常に抽象的な方法を提供しています。

シグナルを使って二つのプロセスは互いに通信する事ができる。 プロセスに名前をつける事によって、コマンドライン上であなたのプログラムを調べてる他のユ〜アと通信できる。 exitコードによって、あなた自身を見て(looking after)いるプロセスに成功/失敗メッセージを送る事ができる。

Farewell, But Not Goodbye

最後だ。おめでとう! でももうちょっとがんばれや。

ネットワークとかやってねーし。他でやる。

付録呼んでね。

なんかあったら連絡よろ。

Happy Coding!

Appendix: How Resque Manages Processes

有名なジョブキュー実装のReque について。プロセスを効率的に管理している。特にfork(2)を同時実行性やスピードのためではなくメモリの管理のために使用している。

To understand why Resque works the way it does we need a basic understanding of how the system works なぜResqueがその方法を使っているのか理解するにどのようにシステムが動作しているか基本的な理解を必要とする

The Architecture

from readme Resque is a Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later Resqueはbackground jobを生成するためのRedisを使用するライブラリです。 それらのjobは複数のキューに配置し、後から処理します。

Forking for Memory Management

この下のコード見てみよう

このコードはResqueに毎回実行されて少しずつジョブを減らす Forkingの小を見てたら if/elseスタイルにはもう慣れてるよね。じゃなかったらすぐ読め! さあ親プロセスから見てみっか

srand # Reseedingはバグ対策だ。

procline ...

proclineはResque内のcurrent processの名前を更新してる $0を使ってcurrent process名を変更できるけどprogrammaticじゃない方法なかったよね? これは Resqueの解決策だ。 proclineはcurrent processの名前を設定する。

Process.wait(@child) Process.waitの章を(以下略 @child変数はfrokの結果だ。 親プロセスでは子プロセスのidが入っている。ここは子プロセスが終わるまで親プロセスがブロックされる。

じゃあ子プロセスはどうなん?

procline ... if/elseどっちでもproclineを呼んでるよね。 同じロジックなんだけど、別のプロセスから呼ばれるよ。 親、子プロセスそれぞれ別の名前が設定される。

perform (job, &block) ここで子プロセスがジョブを実行してる

exit! ... ここで子プロセス終わる(@cant_forkはどこから?)

Why Bother?(なんでこんなことやってんの?)

最初の章で書いたけど、Resqueは同時に実行したり早くしたりしたくてやってんじゃないんだ。 実際、余計な事やってるから遅くなってる じゃあなんでわざわざ?なんでプロセス作ってんの?

Resqueはfork(2)を使ってワーカーのメモリ使用量が膨張しないようにしてんだ。 ResqueのworkerをforkしたときRubyVMにどんな影響があんのか見てみよう。

fork(2)を再度実行して、新しいプロセスを作るとオリジナルプロセスの完全なコピーができる。 オリジナルプロセスはこの場合、preloadされたアプリケーションでそれ以外は何もない そう、僕らはforkされた後はアプリケーション環境がロード済みのプロセスができるって知ってるよね?

子プロセスが少しずつタスクをこなしていくと、メモリ使用量がダメになっていく。 あるバックグランドジョブが画像をメモリに読んで処理するとか、ActiveRecordオブジェクトをDBから読み混むとか、他のメモリをたくさん使う操作をする。子プロセスがジョブを終えてexitすると、そいつのメモリはOSが掃除してくれるんだ。で、オリジナルプロセスが再開するけど、それはあぷリケーション環境だけを読んだやつなんだ。

何回ジョブをResqueが実行しても、メモリ使った形跡は消えちまう。これはジョブを実行して、メモリ使用量が急増したとしても常に良い感じの状態に戻るって事だ。

Dosen't GC clean up for us? GCは掃除してくんないの?

そりゃするさ、けどそれはgreat jobじゃない。It dose an OK job. 確かにMRIのGCは頑張ってメモリ開放してくれるけど、そんな必要は無いんだ。 Ruby VMは起動したときに特定のブロックをカーネルによってメインメモリに確保する. When it uses up all that it has it needs to ask for another block of main memory from the kernel.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment