ValueTask & Mengelakkan Peruntukan
Gunakan ValueTask untuk mengurangkan peruntukan heap dalam laluan panas, fahami kekangannya dan elakkan perangkap penyalahgunaan biasa.
ValueTask & Mengelakkan Peruntukan ialah pelajaran Akademi C# percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Akademi C#, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Akademi C# merangkumi sejumlah 4 pelajaran.
Masalah Peruntukan dengan Task
Task<T> ialah jenis rujukan — setiap kaedah async memperuntukkan Task pada heap, walaupun hasilnya tersedia secara segerak (contohnya daripada cache). Dalam laluan panas, keadaan ini boleh menyebabkan tekanan GC yang ketara. ValueTask<T> menyelesaikan masalah ini.
Apakah ValueTask?
ValueTask<T> ialah struct yang boleh mewakili sama ada hasil yang tersedia secara segerak atau operasi tak segerak yang masih menunggu. Apabila hasil tersedia secara segerak, tiada peruntukan heap diperlukan.
// Task<T>: always allocates, even when result is cached
public async Task<string> GetCached_Task() =>
_cache.TryGetValue("key", out var v) ? v : await FetchAsync();
// ValueTask<T>: zero allocation when value is cached
public ValueTask<string> GetCached_ValueTask() =>
_cache.TryGetValue("key", out var v)
? ValueTask.FromResult(v) // no allocation
: new ValueTask<string>(FetchAsync()); // allocation only when neededMengembalikan ValueTask daripada Antara Muka
Gunakan ValueTask<T> dalam kaedah antara muka yang kerap dipanggil dan sering selesai secara segerak. Pengguna menggunakannya sama seperti Task<T>.
public interface IProductRepository
{
// ValueTask: often completes synchronously from cache
ValueTask<Product?> GetByIdAsync(int id);
// Task: always async (DB query)
Task<List<Product>> SearchAsync(string query);
}
// Consumption is identical to Task:
var product = await _repo.GetByIdAsync(42);
var results = await _repo.SearchAsync("keyboard");ValueTask dengan IValueTaskSource
Untuk prestasi ekstrem, laksanakan IValueTaskSource<T> bagi mengumpulkan objek keadaan sokongan dalam kumpulan. Ini mengelakkan semua peruntukan walaupun untuk penyelesaian tak segerak — pendekatan yang digunakan secara dalaman oleh kod soket dan I/O .NET.
// In most cases, use the simple ValueTask approach.
// IValueTaskSource is for library authors needing zero-alloc async at extreme scale.
// Example: System.IO.Pipelines uses this internally
var result = await pipe.Reader.ReadAsync(ct);
// ReadAsync returns ValueTask<ReadResult> backed by IValueTaskSource
// -- zero allocation for every read even under high throughputKekangan ValueTask: Await Hanya Sekali
Peraturan kritikal: ValueTask<T> mesti digunakan dengan await paling banyak sekali, dan anda tidak boleh memanggil .Result sebelum ia selesai. Pelanggaran ini menyebabkan tingkah laku tidak ditentukan.
var vt = repo.GetByIdAsync(42);
// BAD: await multiple times
var a = await vt; // OK
var b = await vt; // UNDEFINED BEHAVIOR — don't do this!
// BAD: two concurrent awaits
var t1 = vt.AsTask(); // converts to Task (safe to share)
var t2 = vt.AsTask(); // second AsTask() on same ValueTask — WRONG
// GOOD: if you need multiple awaits, convert to Task
var task = repo.GetByIdAsync(42).AsTask();
var r1 = await task;
var r2 = await task; // OK — Task can be awaited multiple timesPanduan Membuat Keputusan ValueTask<T> berbanding Task<T>
Gunakan ValueTask<T> hanya apabila pemprofilan menunjukkan tekanan peruntukan daripada kaedah tak segerak. Jangan gunakannya di mana-mana — ia menambah kerumitan tanpa manfaat dalam kod yang jarang dipanggil.
// USE ValueTask when:
// 1. The method often completes synchronously (cache hit)
// 2. The method is on a hot path called millions of times/sec
// 3. You're writing a library with high-throughput I/O
// USE Task when:
// 1. The result is always async
// 2. The method might be awaited multiple times
// 3. You use Task.WhenAll / Task.WhenAny
// 4. You store the task in a variable and share itValueTask Tanpa Generik
ValueTask (tanpa generik) berfungsi untuk kaedah yang mengembalikan Task (tak segerak tanpa nilai). Gunakannya untuk kaedah yang kerap dipanggil dan sering selesai secara segerak.
public interface ICache
{
// Often a no-op when value exists — ValueTask avoids allocation
ValueTask SetAsync(string key, string value);
ValueTask InvalidateAsync(string key);
}
public class InMemoryCache : ICache
{
private readonly Dictionary<string, string> _data = new();
public ValueTask SetAsync(string key, string value)
{
_data[key] = value;
return ValueTask.CompletedTask; // no allocation
}
}Mengukur Peruntukan dengan BenchmarkDotNet
Gunakan [MemoryDiagnoser] dalam BenchmarkDotNet untuk mengukur peruntukan bagi setiap operasi. Ini ialah satu-satunya cara yang boleh dipercayai untuk mengesahkan bahawa ValueTask benar-benar membantu.
[MemoryDiagnoser]
public class CacheBenchmark
{
private readonly CachedRepo _repo = new();
[Benchmark]
public async Task<Product?> Task_GetById()
=> await _repo.GetByIdTask(1);
[Benchmark]
public async ValueTask<Product?> ValueTask_GetById()
=> await _repo.GetByIdValueTask(1);
}
// Run: dotnet run -c Release
// Compare Gen0 allocations column — ValueTask should show 0B on cache hitValueTask dalam SocketsHttpHandler
Susunan HTTP .NET menggunakan ValueTask secara meluas secara dalaman. Memahami perkara ini membantu anda menulis klien HTTP berprestasi tinggi yang selaras dengan strategi peruntukan masa jalan.
// HttpClient uses ValueTask-based sockets internally.
// When using HttpClient.GetAsync(), the response is awaited with Task<HttpResponseMessage>.
// For streaming large bodies, use:
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
await using var stream = await response.Content.ReadAsStreamAsync();
// Stream reads internally use ValueTask<int> for zero-allocation I/ODunia Sebenar: Perkhidmatan Cache Laluan Panas
Perkhidmatan cache yang setiap panggilannya berpotensi menjadi cache hit — ValueTask menghapuskan peruntukan pada laluan panas sambil terus menyokong sandaran tak segerak untuk cache miss.
public class ProductCache
{
private readonly Dictionary<int, Product> _cache = new();
private readonly IProductRepository _repo;
public ProductCache(IProductRepository repo) => _repo = repo;
public ValueTask<Product?> GetAsync(int id)
{
// Cache hit: no allocation
if (_cache.TryGetValue(id, out var cached))
return ValueTask.FromResult<Product?>(cached);
// Cache miss: async fetch
return new ValueTask<Product?>(FetchAndCacheAsync(id));
}
private async Task<Product?> FetchAndCacheAsync(int id)
{
var product = await _repo.GetByIdAsync(id);
if (product is not null) _cache[id] = product;
return product;
}
}Semakan Pantas
Apakah peraturan kritikal tentang menggunakan ValueTask
Ringkasan: ValueTask dan Mengelakkan Peruntukan
Intipati utama:
ValueTask<T>: struct yang mengelakkan peruntukan heap apabila hasil tersedia secara segerak- Paling sesuai untuk laluan panas yang kerap selesai secara segerak (cache hit)
- JANGAN SEKALI-KALI gunakan
ValueTask<T>dengan await lebih daripada sekali — gunakan.AsTask()untuk berkongsi - Gunakan
[MemoryDiagnoser]untuk mengesahkan penjimatan peruntukan sebelum mengoptimumkan - Utamakan
Task<T>untuk kegunaan umum; gunakanValueTask<T>hanya apabila pemprofilan memberikan justifikasi
Pelajari C# dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 93
- Pelajaran
- 346
Soalan Lazim
Adakah pelajaran “ValueTask & Mengelakkan Peruntukan” percuma?
Ya — teks penuh “ValueTask & Mengelakkan Peruntukan” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus Akademi C#, tingkat taraf kepada CoddyKit PRO. Kursus Akademi C# merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “ValueTask & Mengelakkan Peruntukan”?
Gunakan ValueTask untuk mengurangkan peruntukan heap dalam laluan panas, fahami kekangannya dan elakkan perangkap penyalahgunaan biasa. Anda berlatih Akademi C# menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Akademi C#?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Akademi C# di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.
Berapa lamakah pelajaran “ValueTask & Mengelakkan Peruntukan” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Akademi C# ini?
Ya. Setiap pelajaran Akademi C# menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- IAsyncEnumerable & await foreach
- System.Threading.Channels
- ValueTask & Mengelakkan Peruntukan
- ConfigureAwait & Konteks Penyegerakan