方法は何だろう?どのようなシナリオでこの方法を使用できますか。
私の最初の考えは、RunSynchronously
は非同期メソッドを呼び出し、.wait()
のようなデッドロックの問題を引き起こすことなく、それを同期的に実行することです。
ただし、 [〜#〜] msdn [〜#〜] によると、
通常、タスクはスレッドプールスレッドで非同期に実行され、呼び出しスレッドをブロックしません。 RunSynchronously()メソッドを呼び出して実行されるタスクは、現在のTaskSchedulerに関連付けられ、呼び出し元のスレッドで実行されます。ターゲットスケジューラが呼び出しタスクでこのタスクの実行をサポートしていない場合、タスクはスケジュールに従って実行されるようにスケジュールされ、呼び出しスレッドはタスクの実行が完了するまでブロックします
タスクが呼び出しスレッドで実行される場合、ここにTaskSchedulerが必要なのはなぜですか?
RunSynchronously
は、タスクをいつ開始するかの決定を現在のタスクスケジューラ(または引数として渡されたスケジューラ)に委任します。
なぜそこにあるのかはわからない(おそらく内部またはレガシー使用)が、。NETの現在のバージョンで有用なユースケースを考えるのは難しい。 @ Fabjanはコメントに可能な説明があります 質問に対して。
RunSynchronously
は、スケジューラーに同期的に実行するよう要求しますが、スケジューラーはヒントを無視してスレッドプールスレッドで実行することができ、現在のスレッドは完了するまで同期的にブロックします。
スケジューラは現在のスレッドで実行する必要はなく、すぐに実行する必要はありませんが、一般的なスケジューラ(ThreadPoolTaskSchedulerおよび一般的なUIスケジューラ)で起こると思います。
RunSynchronously
は、タスクが既に開始されている場合、または完了/障害が発生している場合も例外をスローします(つまり、非同期メソッドで使用できないことを意味します)。
このコードは異なる動作を明確にするかもしれません:
Wait
およびResult
はタスクをまったく実行せず、現在のスレッドでタスクの完了を待機し、完了までブロックするため、比較する場合はStart
およびWait
〜RunSynchronously
:
class Scheduler : TaskScheduler
{
protected override void QueueTask(Task task) =>
Console.WriteLine("QueueTask");
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
Console.WriteLine("TryExecuteTaskInline");
return false;
}
protected override IEnumerable<Task> GetScheduledTasks() => throw new NotImplementedException();
}
static class Program
{
static void Main()
{
var taskToStart = new Task(() => { });
var taskToRunSynchronously = new Task(() => { });
taskToStart.Start(new Scheduler());
taskToRunSynchronously.RunSynchronously(new Scheduler());
}
}
StartまたはRunSynchronously
を試してコメントを付けてコードを実行すると、Start
がインラインで試行し、失敗した場合にRunSynchronously
がタスクをスケジューラに試行してキューに入れることがわかります( falseを返します)、キューに入れるだけです。
まず、このコードを見てみましょう。
_public async static Task<int> MyAsyncMethod()
{
await Task.Delay(100);
return 100;
}
//Task.Delay(5000).RunSynchronously(); // bang
//Task.Run(() => Thread.Sleep(5000)).RunSynchronously(); // bang
// MyAsyncMethod().RunSynchronously(); // bang
var t = new Task(() => Thread.Sleep(5000));
t.RunSynchronously(); // works
_
この例では、次のタスクでRunSynchronously
を呼び出そうとしました。
async await
_によって作成された別のpromiseタスク作成後にどのようなステータスになりますか?
すべての「ホット」タスクは、ステータスWaitingForActivation
or WaitingToRun
で作成され、タスクスケジューラに関連付けられます。
メソッドRunSynchronously
は、デリゲートを含み、ステータスがCreated
である 'cold'タスクの操作方法のみを知っています。
結論:
メソッドRunSynchronously
は、「ホット」タスクがなかった場合、またはそれらが広範囲に使用されておらず、特定の目的のために作成された場合におそらく表示されていました。
カスタムTaskScheduler
を使用した「コールド」タスクが必要な場合に使用したい場合があります。
「ホット」タスクを同期的に実行するには(これを避ける必要があります)、task.GetAwaiter().GetResult()
を使用できます。ボーナスとして、AggregateException
のインスタンスではなく、元の例外を返します。