System.Threading.Channels
Bangun alur produsen-konsumen menggunakan Channel, ChannelWriter, dan ChannelReader untuk mengendalikan tekanan balik.
System.Threading.Channels adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.
Apa Itu Kanal?
System.Threading.Channels (diperkenalkan dalam .NET Core 3) menyediakan antrean produsen-konsumen yang berkinerja tinggi dan aman untuk utas. Tidak seperti BlockingCollection, Kanal sepenuhnya asinkron dan hemat alokasi — ideal untuk alur pemrosesan dalam proses.
Membuat Kanal
Kanal dibuat menggunakan pabrik. Pilih unbounded (tanpa batas) atau bounded (kapasitas terbatas dengan tekanan balik). Pabrik mengembalikan Channel<T> dengan Writer dan Reader.
using System.Threading.Channels;
// Unbounded: unlimited capacity, no backpressure
var unbounded = Channel.CreateUnbounded<string>();
// Bounded: max 100 items; writer waits when full
var bounded = Channel.CreateBounded<string>(100);
// Bounded with drop-oldest strategy:
var dropping = Channel.CreateBounded<string>(new BoundedChannelOptions(50)
{
FullMode = BoundedChannelFullMode.DropOldest
});Menulis ke Kanal
Produsen menulis item menggunakan WriteAsync (menunggu jika kanal bounded penuh) atau TryWrite (segera mengembalikan false jika penuh). Tandai penyelesaian dengan Writer.Complete().
var channel = Channel.CreateUnbounded<int>();
// Producer task
var producer = Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
await channel.Writer.WriteAsync(i);
await Task.Delay(10);
}
channel.Writer.Complete(); // signal no more items
});Membaca dari Kanal
Konsumen membaca dengan ReadAllAsync() (pendekatan paling sederhana) atau ReadAsync/TryRead untuk kontrol yang lebih besar. ReadAllAsync selesai ketika penulis memanggil Complete().
// Consumer task
var consumer = Task.Run(async () =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"Processed: {item}");
// Naturally paced — waits for next item
}
Console.WriteLine("Channel completed");
});
await Task.WhenAll(producer, consumer);Beberapa Produsen
Kanal aman untuk utas. Beberapa produsen dapat menulis secara bersamaan — tidak diperlukan penguncian. Panggil Writer.Complete() hanya setelah semua produsen selesai.
var channel = Channel.CreateUnbounded<WorkItem>();
var producers = Enumerable.Range(0, 4).Select(id =>
Task.Run(async () =>
{
for (int i = 0; i < 25; i++)
await channel.Writer.WriteAsync(new WorkItem(id, i));
}));
// Wait for all producers before completing the writer
await Task.WhenAll(producers);
channel.Writer.Complete();Beberapa Konsumen (Penyebaran)
Jalankan beberapa tugas konsumen pada pembaca kanal yang sama untuk memparalelkan pemrosesan. Setiap item dikirim tepat kepada satu konsumen (dibagi, bukan disiarkan).
var channel = Channel.CreateBounded<WorkItem>(100);
// 4 parallel consumers
var consumers = Enumerable.Range(0, 4).Select(id =>
Task.Run(async () =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
await ProcessItemAsync(item);
Console.WriteLine($"Consumer {id} processed {item.Id}");
}
}));
await Task.WhenAll(consumers);Pola Alur Pemrosesan
Rangkai kanal menjadi alur pemrosesan: setiap tahap membaca dari satu kanal, memproses item, lalu menulis ke kanal berikutnya. Tahap-tahap berjalan secara bersamaan dengan tekanan balik alami.
// Stage 1: raw data
var stage1 = Channel.CreateBounded<string>(50);
// Stage 2: parsed
var stage2 = Channel.CreateBounded<ParsedRecord>(50);
// Stage 3: enriched
var stage3 = Channel.CreateBounded<EnrichedRecord>(50);
var parse = ParseStageAsync(stage1.Reader, stage2.Writer);
var enrich = EnrichStageAsync(stage2.Reader, stage3.Writer);
var persist = PersistStageAsync(stage3.Reader);
await Task.WhenAll(parse, enrich, persist);Tekanan Balik dengan Kanal Bounded
Kanal bounded secara otomatis menerapkan tekanan balik: ketika kanal penuh, WriteAsync menangguhkan produsen hingga konsumen mengosongkan item. Tidak diperlukan kode pembatasan laju secara manual.
// Bounded channel: max 10 items
var channel = Channel.CreateBounded<string>(10);
// Fast producer
var producer = Task.Run(async () =>
{
for (int i = 0; i < 1000; i++)
{
// WriteAsync waits when channel has 10 items
await channel.Writer.WriteAsync($"item-{i}");
// Producer is naturally slowed to consumer speed
}
channel.Writer.Complete();
});
// Slow consumer
var consumer = Task.Run(async () =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
await Task.Delay(50); // simulate slow processing
Console.WriteLine(item);
}
});Penanganan Kesalahan dalam Kanal
Teruskan pengecualian ke Writer.Complete(exception) untuk meneruskan kesalahan kepada semua pembaca yang sedang menunggu. Pembaca menerima pengecualian saat kanal dibaca berikutnya.
var channel = Channel.CreateUnbounded<int>();
var producer = Task.Run(async () =>
{
try
{
for (int i = 0; i < 100; i++)
{
if (i == 50) throw new Exception("Producer failed at 50");
await channel.Writer.WriteAsync(i);
}
channel.Writer.Complete();
}
catch (Exception ex)
{
channel.Writer.Complete(ex); // propagate to reader
}
});
try
{
await foreach (var item in channel.Reader.ReadAllAsync())
Console.WriteLine(item);
}
catch (Exception ex)
{
Console.Error.WriteLine($"Channel error: {ex.Message}");
}Praktik Nyata: Antrean Tugas Latar Belakang
Antrean tugas latar belakang yang menggunakan layanan ter-host dan kanal: permintaan HTTP memasukkan tugas ke antrean; pekerja latar belakang memprosesnya satu per satu.
public class JobQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue
= Channel.CreateBounded<Func<CancellationToken, Task>>(100);
public ChannelWriter<Func<CancellationToken, Task>> Writer => _queue.Writer;
public ChannelReader<Func<CancellationToken, Task>> Reader => _queue.Reader;
}
public class JobProcessor : BackgroundService
{
private readonly JobQueue _queue;
public JobProcessor(JobQueue q) => _queue = q;
protected override async Task ExecuteAsync(CancellationToken ct)
{
await foreach (var job in _queue.Reader.ReadAllAsync(ct))
await job(ct);
}
}Pemeriksaan Singkat
Apa yang terjadi ketika produsen memanggil WriteAsync pada kanal bounded yang penuh?
Ringkasan: System.Threading.Channels
Inti penting:
- Kanal menyediakan antrean produsen-konsumen berkinerja tinggi dan asli asinkron
- Unbounded: tanpa batas; Bounded: kapasitas terbatas dengan tekanan balik atau strategi pembuangan
- Beberapa produsen dan konsumen aman digunakan tanpa penguncian
- ReadAllAsync() + await foreach = pola konsumsi yang paling bersih
- Rangkai kanal menjadi alur pemrosesan untuk pemrosesan bersamaan berbasis tahap
- Panggil Writer.Complete() (atau Complete(exception)) untuk menandai akhir aliran
Pertanyaan yang Sering Diajukan
Apakah pelajaran “System.Threading.Channels” gratis?
Ya — teks lengkap “System.Threading.Channels” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “System.Threading.Channels”?
Bangun alur produsen-konsumen menggunakan Channel, ChannelWriter, dan ChannelReader untuk mengendalikan tekanan balik. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai C# Academy?
Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “System.Threading.Channels” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?
Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- IAsyncEnumerable & await foreach
- System.Threading.Channels
- ValueTask & Menghindari Alokasi
- ConfigureAwait & Konteks Sinkronisasi