19

特定の一連の操作 (HTTP 呼び出し) に対して一度に複数のタスクを実行しないようにするクラスまたはパターンを実装したいと考えています。タスクの呼び出しは、異なるスレッドからランダムに発生する可能性があります。呼び出し元が呼び出しを try-catch でラップすることによって例外を処理できるように、async-await パターンを利用したいと考えています。

以下は、意図した実行フローの図です。

ここに画像の説明を入力

呼び出し元からの疑似コード:

try {
    Task someTask = GetTask();
    await SomeScheduler.ThrottledRun(someTask);
} 
catch(Exception ex) { 
    // Handle exception
}

ここでのクラスは、ソリューションによってTaskは代わりのクラスになる場合があります。Action

この質問で「スケジュール」という言葉を使用する場合、必ずしも.NET Task Schedulerに関連して使用しているわけではないことに注意してください。async-await ライブラリについては、どの角度からどのツールを使用してこの問題にアプローチするかを十分に理解していません。ここでは TaskScheduler が関連している可能性がありますが、そうでない可能性もあります。私はTAP パターンのドキュメントを読み、この問題をほぼ解決するパターンを見つけましたが、完全ではありません (インターリーブの章)。

4

1 に答える 1

30

.NET 4.5 には新しいConcurrentExclusiveSchedulerPair型があり (Async CTP に含まれていたかどうかは覚えていません)、これを使用しExclusiveSchedulerて実行を一度に 1 つに制限できますTask

問題をDataflowとして構造化することを検討してください。TaskScheduler制限したいデータフローの部分のブロック オプションにa を渡すだけで簡単です。

Dataflow を使用したくない (または使用できない) 場合は、自分で同様のことを行うことができます。TAP では常に開始済みタスクを返すため、TPL のように「作成」と「スケジューリング」を分離する必要がないことに注意してください。

次のようにs (または戻り値のないラムダ)ConcurrentExclusiveSchedulerPairをスケジュールするために使用できます。Actionasync

public static ConcurrentExclusiveSchedulerPair schedulerPair =
    new ConcurrentExclusiveSchedulerPair();
public static TaskFactory exclusiveTaskFactory =
    new TaskFactory(schedulerPair.ExclusiveScheduler);
...
public static Task RunExclusively(Action action)
{
  return exclusiveTaskFactory.StartNew(action);
}
public static Task RunExclusively(Func<Task> action)
{
  return exclusiveTaskFactory.StartNew(action).Unwrap();
}

これについては、次の点に注意してください。

  • スケジューラーのキューに入れられたConcurrentExclusiveSchedulerPair座標のみの単一インスタンス。Taskの 2 番目のインスタンスはConcurrentExclusiveSchedulerPair最初のインスタンスから独立しているため、調整するシステムのすべての部分で同じインスタンスが使用されていることを確認する必要があります。
  • メソッドは、asyncデフォルトでは、TaskSchedulerそれを開始した同じ場所で再開します。つまり、あるasyncメソッドが別のメソッドを呼び出した場合async、「子」メソッドは親の を「継承」しTaskSchedulerます。どのメソッドも、使用asyncすることで続行をオプトアウトできます(その場合、スレッド プールで直接続行されます)。TaskSchedulerConfigureAwait(false)
于 2012-08-22T08:50:39.040 に答える