ValueTask ve Ayırmalardan Kaçınma
Yoğun kullanılan yollarda yığın ayırmalarını azaltmak için ValueTask kullanın, kısıtlamalarını anlayın ve yaygın yanlış kullanımlardan kaçının.
ValueTask ve Ayırmalardan Kaçınma, CoddyKit'te ücretsiz bir C# Academy dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, C# Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. C# Academy kursu toplamda 4 dersten oluşur.
Task ile Bellek Tahsisi Sorunu
Task<T> bir başvuru türüdür — her async yöntemi, sonuç eş zamanlı olarak kullanılabilir olsa bile (örneğin önbellekten geldiğinde) yığında bir Task tahsis eder. Yoğun kullanılan yollarda bu durum önemli bir GC baskısına yol açabilir. ValueTask<T> bu sorunu çözer.
ValueTask Nedir?
ValueTask<T>, eş zamanlı olarak kullanılabilen bir sonucu veya bekleyen bir asenkron işlemi temsil edebilen bir struct'tır. Sonuç eş zamanlı olarak hazır olduğunda yığın tahsisine gerek kalmaz.
// 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 neededArayüzden ValueTask Döndürme
Sık çağrılan ve çoğu zaman eş zamanlı olarak tamamlanan arayüz yöntemlerinde ValueTask<T> kullanın. Tüketiciler bunu Task<T> ile tamamen aynı şekilde kullanır.
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");IValueTaskSource ile ValueTask
En yüksek performans için, destekleyen durum nesnesini havuzlamak üzere IValueTaskSource<T> uygulayın. Bu, asenkron tamamlanmalarda bile tüm tahsisleri ortadan kaldırır — .NET'in yuva ve G/Ç kodunda dahili olarak kullanılır.
// 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 throughputValueTask Kısıtlamaları: Yalnızca Bir Kez Bekleme
Kritik kural: bir ValueTask<T> en fazla bir kez await edilmelidir ve tamamlanmadan önce .Result çağrılamaz. Bu kurala uymamak tanımsız davranışa neden olur.
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 timesValueTask<T> ve Task<T> için Karar Rehberi
ValueTask<T>'yi yalnızca profil oluşturma, asenkron yöntemlerden kaynaklanan bellek tahsisi baskısını gösterdiğinde kullanın. Her yerde kullanmayın — seyrek çağrılan kodlarda hiçbir yarar sağlamadan karmaşıklık ekler.
// 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 itGenel Tür İçermeyen ValueTask
Genel tür içermeyen ValueTask, Task döndüren (void asenkron) yöntemler için kullanılır. Sık çağrılan ve çoğu zaman eş zamanlı olarak tamamlanan yöntemlerde tercih edin.
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
}
}BenchmarkDotNet ile Tahsisleri Ölçme
İşlem başına tahsisleri ölçmek için BenchmarkDotNet'te [MemoryDiagnoser] kullanın. ValueTask'ın gerçekten yarar sağladığını doğrulamanın tek güvenilir yolu budur.
[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 hitSocketsHttpHandler'da ValueTask
.NET HTTP yığını, dahili olarak ValueTask'ı yoğun biçimde kullanır. Bunu anlamak, çalışma zamanının tahsis stratejisiyle uyumlu, yüksek performanslı HTTP istemcileri yazmanıza yardımcı olur.
// 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/OGerçek Dünya: Yoğun Kullanılan Yol Önbellek Hizmeti
Her çağrının olası bir önbellek isabeti olduğu bir önbellek hizmetinde ValueTask, yoğun kullanılan yolda tahsisleri ortadan kaldırırken önbellek kaçırmaları için asenkron geri dönüşü de destekler.
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;
}
}Hızlı Kontrol
ValueTask
Özet: ValueTask ve Tahsislerden Kaçınma
Önemli çıkarımlar:
ValueTask<T>: sonuç eş zamanlı olarak hazır olduğunda yığın tahsisini önleyen struct- Sık sık eş zamanlı olarak tamamlanan yoğun kullanılan yollar için en uygunudur (önbellek isabetleri)
- Bir
ValueTask<T>için NEVER birden fazla kez await kullanmayın — paylaşmak için.AsTask()kullanın - İyileştirme yapmadan önce tahsis tasarruflarını doğrulamak için
[MemoryDiagnoser]kullanın - Genel kullanımda
Task<T>'yi tercih edin;ValueTask<T>'yi yalnızca profil oluşturma bunu haklı çıkarıyorsa kullanın
Sıkça Sorulan Sorular
“ValueTask ve Ayırmalardan Kaçınma” dersi ücretsiz mi?
Evet — “ValueTask ve Ayırmalardan Kaçınma” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve C# Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. C# Academy kursu toplamda 4 dersten oluşur.
“ValueTask ve Ayırmalardan Kaçınma” dersinde ne öğreneceğim?
Yoğun kullanılan yollarda yığın ayırmalarını azaltmak için ValueTask kullanın, kısıtlamalarını anlayın ve yaygın yanlış kullanımlardan kaçının. C# Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
C# Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te C# Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“ValueTask ve Ayırmalardan Kaçınma” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu C# Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her C# Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- IAsyncEnumerable ve await foreach
- System.Threading.Channels
- ValueTask ve Ayırmalardan Kaçınma
- ConfigureAwait ve Eşitleme Bağlamı