web-dev-qa-db-ja.com

私のインターフェースがTaskを返さなければならない場合、何の操作もしない実装を持つための最善の方法は何ですか?

以下のコードでは、インタフェースのため、クラスLazyBarはそのメソッドからタスクを返さなければなりません(そして引数のために変更することはできません)。 LazyBarsの実装が、すばやく同期的に実行されるという点で変わっている場合 - メソッドからノーオペレーションタスクを返すための最良の方法は何ですか?

私は以下でTask.Delay(0)を使いましたが、関数がlotと呼ばれた場合にこれがパフォーマンス上の副作用があるかどうか知りたいです、毎秒数百回言う):

  • この統語的な砂糖は何か大きなものにほどきますか?
  • それは私のアプリケーションのスレッドプールを詰まらせ始めますか?
  • Delay(0)を別の方法で処理するのに十分なほどコンパイラのクリーバーはありますか?
  • return Task.Run(() => { });は別のものになりますか?

もっと良い方法はありますか?

using System.Threading.Tasks;

namespace MyAsyncTest
{
    internal interface IFooFace
    {
        Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
    }

    /// <summary>
    /// An implementation, that unlike most cases, will not have a long-running
    /// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
    /// </summary>
    internal class LazyBar : IFooFace
    {
        #region IFooFace Members

        public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
        {
            // First, do something really quick
            var x = 1;

            // Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations?
            // Is it a real no-op, or if I call this a lot, will it adversely affect the
            // underlying thread-pool? Better way?
            return Task.Delay(0);

            // Any different?
            // return Task.Run(() => { });

            // If my task returned something, I would do:
            // return Task.FromResult<int>(12345);
        }

        #endregion
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Test();
        }

        private static async void Test()
        {
            IFooFace foo = FactoryCreate();
            await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
            return;
        }

        private static IFooFace FactoryCreate()
        {
            return new LazyBar();
        }
    }
}
358
Jon Rea

Task.FromResult(0)またはTask.FromResult<object>(null)を使用すると、何もしない式でTaskを作成するよりもオーバーヘッドが少なくなります。結果が決まっているTaskを作成するときには、スケジューリングのオーバーヘッドはありません。


今日は、これを達成するために Task.CompletedTask を使用することをお勧めします。

518
Reed Copsey

Task.FromResultの使用について Reed Copseyの答え に追加するには、完了したタスクのすべてのインスタンスが同じであるため、既に完了したタスクをキャッシュするとパフォーマンスをさらに向上させることができます。

public static class TaskExtensions
{
    public static readonly Task CompletedTask = Task.FromResult(false);
}

TaskExtensions.CompletedTaskを使用すると、アプリドメイン全体で同じインスタンスを使用できます。


最新バージョンの.Net Framework(v4.6) では、 Task.CompletedTask staticプロパティを使用してそれを追加しています。

Task completedTask = Task.CompletedTask;
168
i3arnon

Task.Delay(0)は、完成したTaskのキャッシュされたコピーであるため、受け入れられた答えのように良いアプローチでした。

4.6以降、目的がより明確になったTask.CompletedTaskがありますが、Task.Delay(0)が単一のキャッシュされたインスタンスを返すだけでなく、Task.CompletedTaskと同様に同じ単一のキャッシュされたインスタンスを返します。

どちらのキャッシュされた性質も一定であることが保証されますが、最適化としてのみ実装依存である実装依存の最適化として(つまり、実装がまだ有効なものに変更されても正しく機能します)Task.Delay(0)の使用受け入れられた答えよりも優れていました。

33
Jon Hanna

最近これに遭遇し、メソッドが無効であることについての警告/エラーを受け続けました。

私たちはコンパイラを作り出すことを目的としています。

    public async Task MyVoidAsyncMethod()
    {
        await Task.CompletedTask;
    }

これはこれまでのところここですべてのアドバイスの中で最高を一緒にもたらします。実際にメソッドで何かをしているのでなければ、returnステートメントは必要ありません。

14

私は.Net 4.6のTask completedTask = Task.CompletedTask;ソリューションを好むが、別のアプローチはメソッドを非同期とマークしてvoidを返すことである:

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

警告が表示されます(CS1998 - 待機式のない非同期関数)が、これは無視しても安全です。

3
Remco te Wierik
return Task.CompletedTask; // this will make the compiler happy
3
Xin

指定した型を返さなければならない場合:

Task.FromResult<MyClass>(null);
1
trashmaker_