DEV Community

Cover image for Async/Await di .NET Bisa Boros Resource Kalau Tanpa Limit πŸš€πŸ›‘
Insight 105
Insight 105

Posted on

Async/Await di .NET Bisa Boros Resource Kalau Tanpa Limit πŸš€πŸ›‘

Banyak dari kita berpikir bahwa menggunakan async/await secara otomatis membuat aplikasi kita "skalabel". Tapi kenyataannya, tanpa mekanisme pembatasan (throttling), kode async justru bisa menjadi senjata makan tuan yang menghabiskan resource server dalam sekejap.

Di artikel ini (dan video YouTube terbaru saya), kita akan bahas kenapa Task.WhenAll tanpa limit itu berbahaya dan bagaimana SemaphoreSlim menyelamatkan server kamu.

Masalah: Ilusi Paralelisme yang Tak Terbatas

Bayangkan kamu harus memproses 1.000 data menggunakan API eksternal. Kode yang paling umum ditulis adalah seperti ini:

var tasks = dataList.Select(d => CallExternalApiAsync(d));
await Task.WhenAll(tasks); 

Enter fullscreen mode Exit fullscreen mode

Apa yang terjadi di balik layar?
.NET akan mencoba menjalankan 1.000 task tersebut hampir secara bersamaan. Jika setiap task membuka koneksi HTTP atau koneksi database, kamu akan mengalami:

  1. Socket Exhaustion: Server kehabisan port untuk koneksi keluar.
  2. Database Pool Starvation: Request lain tertahan karena semua koneksi DB sedang dipakai.
  3. RAM Spike: Setiap task membawa state machine dan alokasi memori sendiri-sendiri.

Hasilnya? Server "hang", request timeout, dan user kecewa.


Solusi: Memasang "Kran" dengan SemaphoreSlim

SemaphoreSlim adalah cara paling ringan di .NET untuk membatasi berapa banyak task yang boleh berjalan secara konkuren.

Cara Implementasi yang Benar:

// Batasi maksimal 10 operasi konkuren
using var semaphore = new SemaphoreSlim(10);

var tasks = dataList.Select(async d => 
{
    await semaphore.WaitAsync(); // Antre di sini
    try 
    {
        await CallExternalApiAsync(d);
    }
    finally 
    {
        semaphore.Release(); // Lepas slot untuk task berikutnya
    }
});

await Task.WhenAll(tasks);

Enter fullscreen mode Exit fullscreen mode

Dengan kode ini, meskipun kamu punya 1.000 data, hanya 10 data yang diproses secara bersamaan. Resource server tetap terjaga, dan aplikasi tetap responsif.


3 Hal Penting yang Sering Dilupakan:

  1. Gunakan `try...finally: Jangan pernah lupa memanggil Release() di blok finally`. Jika tidak, slot semaphore akan "bocor" dan aplikasi kamu akan mengalami deadlock (berhenti total).
  2. Tentukan Limit yang Rasional: Jangan asal pasang angka. Sesuaikan limit dengan kemampuan resource (misal: jumlah koneksi maksimal di Database Pool kamu).
  3. Semaphore vs Lock: Ingat, jangan gunakan lock biasa untuk kode async. lock memblokir thread, sedangkan WaitAsync() membebaskan thread untuk mengerjakan hal lain sambil mengantre.

Kesimpulan

async/await memberikan kita kekuatan, tapi SemaphoreSlim memberikan kita kendali. Jangan biarkan server kamu tumbang hanya karena mencoba melakukan terlalu banyak hal di waktu yang sama.

Top comments (0)