複雑な依存関係をもつgoroutine群を管理するためのモジュールです。
階層構造の依存関係をもつ処理群を、一連のミッションとして見立てて管理することを目指したので、このような名前になってます。
goroutineの関係が複雑になると、go標準のパッケージ(sync.WaitGroupやcontext.Context)で実装すると、select文まみれになるので、その対策として作られました。
階層的に管理できるので、グループ単位部分的なキャンセルも、全体を一斉にキャンセルすることも可能になっています。
go標準のsync.WaitGroupおよび、context.Contextとの大きな違いは以下のとおり。
- 追加のコード無しに、複数のタスクグループを連携させることが出来る。(sync.WaitGroupとの違い)
- 安全に動的なgoroutineの追加に対応できる。(sync.WaitGroupとの違い)
- 複数の箇所からキャンセル出来る。(context.Contextとの違い)
- context.ContextのDeadline()やValue()という余計な機能はない。
- タイムアウト処理は
github.com/l4go/timer
を使う前提。
- タイムアウト処理は
import "github.com/l4go/task"
vendoringして使うことを推奨します。
Missionが、提供する機能は、以下のものとその組み合わせです。
- タスクの終了をDone()メソッドで、親のタスクに通知する。
- 子供のタスクの終了を、親のDone()で待ってから終了する。
- Cancel()メソッドで、子孫のタスクにキャンセルを通知する。
- Abort()メソッドで、先祖も含めた全部のタスクにキャンセルを通知する。
- 子供のタスク終了の通知を、Done()、Activate()、及び、Recv()メソッドの実行まで、遅延させる。
- キャンセル通知をRecvCancel()からのchannelで受け取って、処理の中断を実装できるようにする。
- 子供のタスク終了をRecvDone()もしくはRecv()からのchannelで受け取り、selectで他の処理と一緒に終了待ち出来る。
sync.WaitGroupでは、生成タスク数が未定の場合、複数タスク生成完了前に生成済みタスクがすべて終了すると、間違った完了通知が起こる問題があります。
この問題への対策が、子供のタスク終了の通知を遅延する機能です。
孫のworkerがある2重のworker構造へ、goroutineにキャンセル処理を実装したコードサンプルです。
比較的シンプルに、複雑なgorutineの完了管理が実装できてることが分かると思います。
トップのタスク管理の*Missionを生成します。 *Mission生成直後は、小の*Missionの終了通知は遅延状態になっています。
New()メソッドで、子供の*Missionを生成できます。
小タスク管理用のMissionを生成します。
サブタスク管理用の*Cancelを生成します。
生成された*Cancelは、*Mission側のCancel処理に連動する状態になっています。 *Cancel側のCancel処理は、Mission側へ連動させていないので、サブタスクの影響を受けません。
*MissionのCancel処理をCancellerへ連動させます。
子のMission終了通知を有効にし、子のMissionの終了を待ってから、自分のMissionを終了させます。
子のMission終了通知を有効にし、自分のMissionを終了させます。子のMissionの終了は待ちません。
子のMissionの終了を待てない特殊な場合に使いますが、非推奨です。
キャンセル情報を、自分及び子孫のMissionに伝播させます。親および祖先には伝播しません。複数箇所から実行されても問題なく動作します。
キャンセル情報を、トップのMissionも含めてすべてのMissionに伝播します。
トップのMissionでCancel()メソッドを実行した時と同じ動作です。
キャンセルの有無を確認します。
処理を開始する前に実施の判断をしたい時に利用します。
キャンセルを通知するchannelを取得します。
キャンセルされるとこのchannelがcloseされます。
子のMission終了通知を有効にしてから、子のMissionがすべて終了した状態を示すchannelを取得します。
子のMissionをすべて生成する(New()メゾッドを呼び終わる)前にRecv()メソッドを呼ぶと誤動作します。
別のgoroutingなどで事前に終了待ちの処理を実行したい場合は、RecvDone()メソッドを利用して、後から子のMissionの終了通知を有効にください。
通常は、Done()メソッドもしくは、RecvDone()メソッドの利用が推奨されます。
他のタスク管理と連携させる処理のみに利用するメゾッドで、通常は、Down()メソッドを使えば解決します。
main()関数などで、終了用signalと並行して待つ状況などが想定された適切な用途です。
子のMission終了通知するchannelを取得します。
子のMissionを生成する前に、別のgoroutineから通知用のチャンネルを利用する場合に使います。
Activate()メソッド、Done()メソッド、Recv()メソッドのどれかが実行されると、通知は開始されます。
子のMissionがすべて終了した状態の通知を開始します。
Recv()メソッドやDone()メソッドを実行する前に、通知を開始したい場合に利用します。
Missionをgo標準のcontext.Contextインタフェース互換形式に変換します。
go標準の関数と連携するために使います。
親のMissionを取得します。親のMissionが無い場合は、nilが返ります。
親のMissionをキャンセルするために使います。
全部のMissionをキャンセルするのには、Abort()メソッドを利用してください。