Skip to content

Race

1. 概要

Race は、複数の Observable のうち最初に値を発行したものを「勝者」とし、それ以外のすべての Observable の購読を解除するオペレーターです。

勝者が決定した後は、勝者の Observable からの要素のみが下流へ流れます。従来の Rx では Amb と呼ばれていたオペレーターが、R3 では Race にリネームされています。

2. シグネチャ

2 つの Observable で競争する(オペレーターオーバーロード)

csharp
public static Observable<T> Race<T>(this Observable<T> source, Observable<T> second)

2 つの Observable のうち、先に値を発行した方を採用します。

csharp
source.Race(second)

可変個数の Observable で競争する(ファクトリメソッド)

csharp
public static Observable<T> Race<T>(params Observable<T>[] sources)
public static Observable<T> Race<T>(IEnumerable<Observable<T>> sources)

任意の個数の Observable のうち、最初に値を発行したものを採用します。

csharp
Observable.Race(source1, source2, source3)

overload の使い分け

overload使う場面
Race(Observable<T>)2 つの Observable を競争させる基本的なケース
Race(params Observable<T>[])3 つ以上の Observable を競争させる場合
Race(IEnumerable<Observable<T>>)コレクションとして渡す場合

3. マーブルダイアグラム

Race のマーブルダイアグラム

最初に値を発行した Observable が勝者となり、他の Observable は購読解除されます。以降は勝者の要素のみが下流へ流れます。

4. サンプルコード

csharp
using R3;

var fast = new Subject<string>();
var slow = new Subject<string>();

fast.Race(slow)
    .Subscribe(x => Console.WriteLine(x));

slow.OnNext("遅い");     // slow が先に発行 → slow が勝者
fast.OnNext("速い");     // 出力なし(fast は購読解除済み)
slow.OnNext("継続");     // 出力: 継続

複数ソースでの競争:

csharp
using R3;

// 複数のサーバーにリクエストを送り、最初に応答したものを採用
var server1 = FetchFromServer("https://server1.example.com/api");
var server2 = FetchFromServer("https://server2.example.com/api");
var server3 = FetchFromServer("https://server3.example.com/api");

Observable.Race(server1, server2, server3)
    .Subscribe(response => ProcessResponse(response));

5. 補足

Merge との違い

Merge はすべてのソースに同時に購読し、届いた値をすべて下流に流します。Race は最初に値を発行したソースのみを採用し、他は即座に購読解除します。

特性RaceMerge
採用するソース最初に発行した 1 つだけすべて
敗者の扱い購読解除継続して購読
典型的な用途冗長系からの最速応答複数イベントの集約

旧名称 Amb について

R3 では、従来の Reactive Extensions で Amb(ambiguous の略)と呼ばれていたオペレーターが Race にリネームされています。Amb は互換性のために残されていますが、[Obsolete] 属性が付与されているため、新しいコードでは Race を使用してください。

ファクトリメソッド版との違い

ファクトリメソッド版 Race は、Observable.Race(source1, source2, source3) のように複数ソースをまとめて指定する場合に使います。2 つのソースだけを競争させる場合は、このオペレーター版の source.Race(second) が読みやすくなります。