web-dev-qa-db-ja.com

Task.FromResult()とTask.Run()の比較

最近、asyncメソッドが同期的に実行されても、とにかくタスクを返すというかなり多くの状況に遭遇しました。

public virtual Task CreateAsync(TUser user)
{
    ThrowIfDisposed();
    if (user == null) throw new ArgumentNullException("user");
    Context.Save(user);
    Context.Flush();
    return Task.FromResult(0);
}

おそらく、長時間実行される可能性のある操作をスレッドにディスパッチし、まだアクティブなタスクを返して、本当に待機することをお勧めします。

public virtual Task CreateAsync(TUser user)
{
    ThrowIfDisposed();
    if (user == null) throw new ArgumentNullException("user");
    return Task.Run(() =>
    {
        Context.Save(user);
        Context.Flush();
    });
}

ただし、TPLスレッドをスピンオフするだけでは最も安全な方法ではないのではないかと疑っています。これら2つの異なるパターンに関する解説はありますか?

22
ProfK

メソッドが同期型の場合、最初にTaskを返さないでください。従来の同期メソッドを作成するだけです。

何らかの理由でそれが不可能な場合(たとえば、非同期インターフェースを実装している場合)Task.FromResultを使用して完了したタスクを返すか、この場合はさらに良い場合はTask.CompletedTask(.NET 4.6で追加)を使用するよりもはるかに良いTask.Runの実装:

public virtual Task CreateAsync(TUser user)
{
    // ...
    return Task.CompletedTask;
}

APIのコンシューマーがTask- returningメソッドが同期して実行されないことを強く気にしている場合は、Task.Run自体を使用して確認できます。

非同期メソッドは、最終的に非同期に継続する場合でも、かなりの同期部分(最初に待機する前の部分)が存在する可能性があることに注意してください。 とにかく、非同期メソッドがTaskをすぐに返すとは限りません。

19
i3arnon

Task.FromResultは実際にはタスクを作成または実行しませんが、返された結果をタスクオブジェクトにラップするだけです。私はUnit Testsで個人的に使用しており、Asyncメソッドをシミュレートする必要があります。もちろん、単体テストで実際のタスクを実行したくありません。

さらにTask.Runは実際にタスクを作成し、TaskSchedulerでタスクを実行します。 AsyncプログラミングをしているときはTask.Runの使用は推奨されません。タスクではなくawaitを使用してください。 Stephen Clearyによる タスクの実行と非実行 を参照してください。

10
vendettamit