162

クラスCancellationTokenに加えて.NET 構造体が導入された理由の根拠を探しています。API の使用方法CancellationTokenSourceは理解していますが、そのように設計されている理由も理解したいと考えています。

つまり、なぜ私たちは持っているのですか:

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);

...
public void SomeCancellableOperation(CancellationToken token) {
    ...
    token.ThrowIfCancellationRequested();
    ...
}

次のように直接渡す代わりにCancellationTokenSource

var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);

...
public void SomeCancellableOperation(CancellationTokenSource cts) {
    ...
    cts.ThrowIfCancellationRequested();
    ...
}

これは、トークンを渡すよりもキャンセル状態のチェックが頻繁に行われるという事実に基づくパフォーマンスの最適化ですか?

それで、それCancellationTokenSourceは と update を追跡できCancellationTokens、各トークンのキャンセルチェックはローカルフィールドアクセスですか?

どちらの場合も、ロックのない volatile bool で十分であることを考えると、なぜそれが高速になるのかはまだわかりません。

ありがとう!

4

5 に答える 5

140

私はこれらのクラスの設計と実装に携わっていました。

簡単な答えは「関心の分離」です。さまざまな実装戦略があり、少なくとも型システムと初期学習に関してはより単純なものがあることはまったく事実です。ただし、CTS と CT は非常に多くのシナリオ (深いライブラリ スタック、並列計算、非同期など) での使用を想定しているため、多くの複雑なユース ケースを念頭に置いて設計されています。これは、パフォーマンスを犠牲にすることなく、成功するパターンを奨励し、アンチパターンを思いとどまらせることを意図した設計です。

API の誤動作に対してドアが開いたままになっていると、キャンセル設計の有用性がすぐに損なわれる可能性があります。

CancellationTokenSource== 「キャンセルトリガー」、およびリンクされたリスナーを生成します

CancellationToken== 「キャンセルリスナー」

于 2013-03-28T00:40:44.373 に答える
65

それらは技術的な理由ではなく、意味的な理由で分離されています。ILSpyの下での の実装を見ると、 CancellationTokenそれは単なるラッパーであることがわかりますCancellationTokenSource(したがって、参照を渡すのとパフォーマンスの点で違いはありません)。

これらは、物事をより予測可能にするために、この機能の分離を提供します。メソッド a を渡すと、CancellationTokenそれをキャンセルできるのは自分だけであることがわかります。確かに、メソッドは引き続き をスローできますTaskCancelledExceptionが、CancellationTokenそれ自体 (および同じトークンを参照する他のメソッド) は安全なままです。

于 2013-01-08T13:28:23.240 に答える
10

CancellationToken構造体であるため、メソッドに渡すために多くのコピーが存在する可能性があります。

CancellationTokenSourceソースを呼び出すときに、トークンのすべてのコピーの状態を設定しますCancelこのMSDNページを参照してください

設計の理由は、関心の分離と構造体の速度の問題かもしれません。

于 2013-01-08T13:26:28.617 に答える
2

CancellationTokenSource、何らかの理由でキャンセルを発行する「もの」です。CancellationToken発行したすべての にキャンセルを「ディスパッチ」する方法が必要です。これは、たとえば、ASP.NET が要求が中止されたときに操作をキャンセルできる方法です。各リクエストには、CancellationTokenSource発行したすべてのトークンにキャンセルを転送する があります。

ところで、これはユニット テストに最適です。独自のキャンセル トークン ソースを作成し、トークンを取得Cancelし、ソースを呼び出して、キャンセルを処理する必要があるコードにトークンを渡します。

于 2013-01-08T13:30:39.787 に答える