Dalam kode di bawah ini, karena antarmuka, kelas LazyBar
harus mengembalikan tugas dari metode itu (dan demi argumen tidak dapat diubah). Jika LazyBar
implementasi tidak biasa terjadi karena berjalan dengan cepat dan serempak - apa cara terbaik untuk mengembalikan tugas Tanpa Operasi dari metode ini?
Saya telah membahas di Task.Delay(0)
bawah ini, namun saya ingin tahu apakah ini memiliki efek samping kinerja jika fungsinya disebut banyak (demi argumen, katakan ratusan kali per detik):
- Apakah gula sintaksis ini melepaskan angin ke sesuatu yang besar?
- Apakah itu mulai menyumbat kumpulan utas aplikasi saya?
- Apakah golok compiler cukup untuk menangani secara
Delay(0)
berbeda? - Apakah
return Task.Run(() => { });
akan berbeda?
Apakah ada cara yang lebih baik?
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<object>(null)
.Jawaban:
Menggunakan
Task.FromResult(0)
atauTask.FromResult<object>(null)
akan dikenakan biaya lebih sedikit daripada membuatTask
dengan tanpa-op ekspresi. Saat membuatTask
dengan hasil yang ditentukan sebelumnya, tidak ada overhead penjadwalan yang terlibat.Hari ini, saya akan merekomendasikan menggunakan Task.CompletedTask untuk mencapai ini.
sumber
return default(YourReturnType);
Task.CompletedTask
mungkin melakukan trik! (tetapi membutuhkan .net 4.6)Untuk menambahkan jawaban Reed Copsey tentang penggunaan
Task.FromResult
, Anda dapat meningkatkan kinerja lebih banyak lagi jika Anda men-cache tugas yang sudah selesai karena semua contoh tugas yang diselesaikan adalah sama:Dengan
TaskExtensions.CompletedTask
Anda dapat menggunakan contoh yang sama di seluruh domain aplikasi.Versi terbaru dari .Net Framework (v4.6) menambahkan hanya itu dengan
Task.CompletedTask
properti statissumber
public Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
jugapublic async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
. Jadi, kita bisareturn CompletedTask;
atauawait CompletedTask;
. Apa yang lebih disukai (mungkin lebih efisien atau lebih kongruen)?Task.Delay(0)
seperti dalam jawaban yang diterima adalah pendekatan yang baik, karena merupakan salinan cache yang sudah diisiTask
.Pada 4.6 ada sekarang
Task.CompletedTask
yang lebih eksplisit dalam tujuannya, tetapi tidak hanyaTask.Delay(0)
masih kembali contoh cache tunggal, itu mengembalikan contoh cache tunggal yang sama seperti halnyaTask.CompletedTask
.Sifat cache dari tidak dijamin untuk tetap konstan, tetapi sebagai optimisations tergantung dari implementasi yang hanya tergantung dari implementasi sebagai optimisations (yaitu, mereka masih akan bekerja dengan benar jika pelaksanaan berubah menjadi sesuatu yang masih berlaku) penggunaan
Task.Delay(0)
adalah lebih baik dari jawaban yang diterima.sumber
Task.CompletedTask
tidak dapat digunakan dalam proyek PCL, bahkan jika saya mengatur versi .net ke 4.6 (profil 7), baru saja diuji dalam VS2017.Task.CompletedTask => Task.Delay(0);
untuk mendukung itu, jadi saya tidak Aku tahu pasti dari atas kepalaku.Baru-baru ini menjumpai ini dan terus mendapatkan peringatan / kesalahan tentang metode yang batal.
Kami berada dalam bisnis menempatkan kompiler dan ini akan membersihkannya:
Sejauh ini, ini menyatukan semua saran terbaik di sini. Pernyataan pengembalian tidak diperlukan kecuali Anda benar-benar melakukan sesuatu dalam metode ini.
sumber
public Task MyVoidAsyncMethod() {}
sepenuhnya sama dengan metode di atas. Jika ada usecase untuk menggunakannya seperti ini, silakan tambahkan kode tambahan.sumber
Ketika Anda harus mengembalikan jenis yang ditentukan:
sumber
Saya lebih suka
Task completedTask = Task.CompletedTask;
solusi. Net 4.6, tetapi pendekatan lain adalah menandai metode async dan mengembalikan void:Anda akan mendapatkan peringatan (CS1998 - Async berfungsi tanpa menunggu ekspresi), tetapi ini aman untuk diabaikan dalam konteks ini.
sumber
Jika Anda menggunakan obat generik, semua jawaban akan memberi kami kesalahan kompilasi. Anda bisa menggunakannya
return default(T);
. Contoh di bawah ini untuk menjelaskan lebih lanjut.sumber
sumber