519

以下のコードでは、インターフェースのために、クラスLazyBarはそのメソッドからタスクを返す必要があります(そして引数のために変更することはできません)。の実装がたまたま迅速かつ同期的に実行されるという点で異常な場合LazyBar、メソッドから操作なしのタスクを返すための最良の方法は何ですか?

以下を参照しましたが、関数が頻繁に呼び出され場合(引数として、1秒間に数百回)、Task.Delay(0)これにパフォーマンスの副作用があるかどうかを知りたいと思います。

  • このシンタックスシュガーは何か大きなものにほどけますか?
  • アプリケーションのスレッドプールが詰まり始めますか?
  • コンパイラークリーバーは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();
        }
    }
}
4

9 に答える 9

742

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


Pre .net 4.6:

Task.FromResult(0)またはを使用すると、no-op式を使用してaをTask.FromResult<object>(null)作成するよりもオーバーヘッドが少なくなります。結果が事前に決定されたTaskを作成する場合、スケジュールのオーバーヘッドは発生しません。Task

于 2012-10-29T18:05:10.403 に答える
201

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

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

これによりTaskExtensions.CompletedTask、アプリドメイン全体で同じインスタンスを使用できます。


最新バージョンの.NetFramework(v4.6)Task.CompletedTaskは、静的プロパティでそれを追加します

Task completedTask = Task.CompletedTask;
于 2014-11-22T02:07:09.643 に答える
44

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

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

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

于 2015-12-22T01:23:19.910 に答える
26

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

私たちはコンパイラーを配置するビジネスを行っており、これによりコンパイラーがクリアされます。

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

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

于 2016-12-13T13:28:54.060 に答える
22
return Task.CompletedTask; // this will make the compiler happy
于 2019-06-24T04:15:23.900 に答える
13

指定されたタイプを返す必要がある場合:

Task.FromResult<MyClass>(null);
于 2019-05-30T20:01:16.943 に答える
2

Task completedTask = Task.CompletedTask;は.Net4.6のソリューションを好みますが、別のアプローチは、メソッドを非同期としてマークし、voidを返すことです。

    public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
    {
    }

警告が表示されます(CS1998-await式のない非同期関数)が、このコンテキストでは無視しても安全です。

于 2016-12-02T14:16:01.270 に答える
-1

ジェネリックスを使用している場合、すべての答えでコンパイルエラーが発生します。を使用できますreturn default(T);。詳細については、以下のサンプルをご覧ください。

public async Task<T> GetItemAsync<T>(string id)
            {
                try
                {
                    var response = await this._container.ReadItemAsync<T>(id, new PartitionKey(id));
                    return response.Resource;
                }
                catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
                {

                    return default(T);
                }

            }
于 2020-02-14T06:37:23.413 に答える
-1
return await Task.FromResult(new MyClass());
于 2020-06-02T14:32:49.900 に答える