以下のコードでは、インタフェースのため、クラスLazyBar
はそのメソッドからタスクを返さなければなりません(そして引数のために変更することはできません)。 LazyBar
sの実装が、すばやく同期的に実行されるという点で変わっている場合 - メソッドからノーオペレーションタスクを返すための最良の方法は何ですか?
私は以下で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();
}
}
}
Task.FromResult(0)
またはTask.FromResult<object>(null)
を使用すると、何もしない式でTask
を作成するよりもオーバーヘッドが少なくなります。結果が決まっているTask
を作成するときには、スケジューリングのオーバーヘッドはありません。
今日は、これを達成するために Task.CompletedTask を使用することをお勧めします。
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;
Task.Delay(0)
は、完成したTask
のキャッシュされたコピーであるため、受け入れられた答えのように良いアプローチでした。
4.6以降、目的がより明確になったTask.CompletedTask
がありますが、Task.Delay(0)
が単一のキャッシュされたインスタンスを返すだけでなく、Task.CompletedTask
と同様に同じ単一のキャッシュされたインスタンスを返します。
どちらのキャッシュされた性質も一定であることが保証されますが、最適化としてのみ実装依存である実装依存の最適化として(つまり、実装がまだ有効なものに変更されても正しく機能します)Task.Delay(0)
の使用受け入れられた答えよりも優れていました。
最近これに遭遇し、メソッドが無効であることについての警告/エラーを受け続けました。
私たちはコンパイラを作り出すことを目的としています。
public async Task MyVoidAsyncMethod()
{
await Task.CompletedTask;
}
これはこれまでのところここですべてのアドバイスの中で最高を一緒にもたらします。実際にメソッドで何かをしているのでなければ、returnステートメントは必要ありません。
私は.Net 4.6のTask completedTask = Task.CompletedTask;
ソリューションを好むが、別のアプローチはメソッドを非同期とマークしてvoidを返すことである:
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
}
警告が表示されます(CS1998 - 待機式のない非同期関数)が、これは無視しても安全です。
return Task.CompletedTask; // this will make the compiler happy
指定した型を返さなければならない場合:
Task.FromResult<MyClass>(null);