Bagikan melalui


Membatalkan daftar tugas

Anda dapat membatalkan aplikasi konsol async jika Anda tidak ingin menunggunya selesai. Dengan mengikuti contoh dalam topik ini, Anda dapat menambahkan cancellation ke aplikasi yang mengunduh konten daftar situs web. Anda dapat membatalkan banyak tugas dengan mengaitkan instance CancellationTokenSource dengan setiap tugas. Jika Anda memilih tombol Enter, Anda membatalkan semua tugas yang belum selesai.

Tutorial ini mencakup:

  • Buat aplikasi konsol .NET baru
  • Menulis aplikasi async yang mendukung cancellation
  • Menunjukkan sinyal cancellation

Prasyarat

Tutorial ini memerlukan hal-hal berikut:

Membuat aplikasi contoh

Membuat aplikasi konsol .NET Core baru. Anda dapat membuatnya dengan menggunakan perintah dotnet new console atau dari Visual Studio. Buka file Program.cs di editor kode favorit Anda.

Ganti menggunakan statement

Ganti penggunaan statement yang ada dengan deklarasi ini:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

Tambahkan bidang

Dalam penentuan class Program, tambahkan ketiga bidang ini:

static readonly CancellationTokenSource s_cts = new CancellationTokenSource();

static readonly HttpClient s_client = new HttpClient
{
    MaxResponseContentBufferSize = 1_000_000
};

static readonly IEnumerable<string> s_urlList = new string[]
{
    "https://learn.microsoft.com",
    "https://learn.microsoft.com/aspnet/core",
    "https://learn.microsoft.com/azure",
    "https://learn.microsoft.com/azure/devops",
    "https://learn.microsoft.com/dotnet",
    "https://learn.microsoft.com/dynamics365",
    "https://learn.microsoft.com/education",
    "https://learn.microsoft.com/enterprise-mobility-security",
    "https://learn.microsoft.com/gaming",
    "https://learn.microsoft.com/graph",
    "https://learn.microsoft.com/microsoft-365",
    "https://learn.microsoft.com/office",
    "https://learn.microsoft.com/powershell",
    "https://learn.microsoft.com/sql",
    "https://learn.microsoft.com/surface",
    "https://learn.microsoft.com/system-center",
    "https://learn.microsoft.com/visualstudio",
    "https://learn.microsoft.com/windows",
    "https://learn.microsoft.com/maui"
};

CancellationTokenSource digunakan untuk mengirimkan request sinyal cancellation ke CancellationToken. HttpClient mengekspos kemampuan untuk mengirim permintaan HTTP dan menerima respons HTTP. s_urlList menampung semua URL yang akan diproses oleh aplikasi.

Memperbarui entry point aplikasi

Entry point utama ke dalam aplikasi konsol adalah metode Main. Ganti metode yang ada dengan berikut:

static async Task Main()
{
    Console.WriteLine("Application started.");
    Console.WriteLine("Press the ENTER key to cancel...\n");

    Task cancelTask = Task.Run(() =>
    {
        while (Console.ReadKey().Key != ConsoleKey.Enter)
        {
            Console.WriteLine("Press the ENTER key to cancel...");
        }

        Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
        s_cts.Cancel();
    });
    
    Task sumPageSizesTask = SumPageSizesAsync();

    Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
    if (finishedTask == cancelTask)
    {
        // wait for the cancellation to take place:
        try
        {
            await sumPageSizesTask;
            Console.WriteLine("Download task completed before cancel request was processed.");
        }
        catch (TaskCanceledException)
        {
            Console.WriteLine("Download task has been cancelled.");
        }
    }
        
    Console.WriteLine("Application ending.");
}

Method yang diperbarui Main sekarang dianggap sebagai Async utama, yang memungkinkan entry point asynchronous ke dalam program yang dapat dieksekusi. Hal tersebut akan menulis beberapa pesan instruksi ke konsol, lalu mendeklarasikan Task instance bernama cancelTask, yang akan membaca penekanan tombol konsol. Jika tombol Enter ditekan, sebuah panggilan ke CancellationTokenSource.Cancel() akan dilakukan. Ini akan memberi sinyal cancellation. Selanjutnya, sumPageSizesTask variabel ditugaskan dari method SumPageSizesAsync. Kedua tugas kemudian diteruskan ke Task.WhenAny(Task[]), yang akan berlanjut ketika salah satu dari dua tugas telah selesai.

Blok kode berikutnya memastikan bahwa aplikasi tidak keluar sampai pembatalan telah diproses. Jika tugas pertama yang harus diselesaikan adalah cancelTask, sumPageSizeTask tugas ditunggu. Jika dibatalkan, ketika ditunggu, itu melempar System.Threading.Tasks.TaskCanceledException. Blok menangkap pengecualian itu, dan mencetak pesan.

Membuat metode ukuran halaman jumlah asinkron

Di bawah metode Main, tambahkan metode SumPageSizesAsync:

static async Task SumPageSizesAsync()
{
    var stopwatch = Stopwatch.StartNew();

    int total = 0;
    foreach (string url in s_urlList)
    {
        int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
        total += contentLength;
    }

    stopwatch.Stop();

    Console.WriteLine($"\nTotal bytes returned:  {total:#,#}");
    Console.WriteLine($"Elapsed time:          {stopwatch.Elapsed}\n");
}

Metode dimulai dengan membuat instans dan memulai Stopwatch. Kemudian melakukan perulangan setiap URL di s_urlList dan memanggil ProcessUrlAsync. Dengan setiap iterasi, s_cts.Token diteruskan ke method ProcessUrlAsync dan kode mengembalikan Task<TResult>, di mana TResult adalah integer:

int total = 0;
foreach (string url in s_urlList)
{
    int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
    total += contentLength;
}

Menambahkan metode proses

Tambahkan metode berikut ProcessUrlAsync di bawah metode SumPageSizesAsync:

static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
{
    HttpResponseMessage response = await client.GetAsync(url, token);
    byte[] content = await response.Content.ReadAsByteArrayAsync(token);
    Console.WriteLine($"{url,-60} {content.Length,10:#,#}");

    return content.Length;
}

Untuk URL tertentu, method akan menggunakan instance client yang disediakan untuk mendapatkan respon sebagai byte[]. InstanceCancellationToken diteruskan ke HttpClient.GetAsync(String, CancellationToken) dan method HttpContent.ReadAsByteArrayAsync(). token digunakan untuk mendaftar request cancellation. Panjang dikembalikan setelah URL dan panjang ditulis ke konsol.

Contoh output aplikasi

Application started.
Press the ENTER key to cancel...

https://learn.microsoft.com                                       37,357
https://learn.microsoft.com/aspnet/core                           85,589
https://learn.microsoft.com/azure                                398,939
https://learn.microsoft.com/azure/devops                          73,663
https://learn.microsoft.com/dotnet                                67,452
https://learn.microsoft.com/dynamics365                           48,582
https://learn.microsoft.com/education                             22,924

ENTER key pressed: cancelling downloads.

Application ending.

Contoh lengkap

Kode berikut adalah teks lengkap dari file Program.cs sebagai contoh.

using System.Diagnostics;

class Program
{
    static readonly CancellationTokenSource s_cts = new CancellationTokenSource();

    static readonly HttpClient s_client = new HttpClient
    {
        MaxResponseContentBufferSize = 1_000_000
    };

    static readonly IEnumerable<string> s_urlList = new string[]
    {
            "https://learn.microsoft.com",
            "https://learn.microsoft.com/aspnet/core",
            "https://learn.microsoft.com/azure",
            "https://learn.microsoft.com/azure/devops",
            "https://learn.microsoft.com/dotnet",
            "https://learn.microsoft.com/dynamics365",
            "https://learn.microsoft.com/education",
            "https://learn.microsoft.com/enterprise-mobility-security",
            "https://learn.microsoft.com/gaming",
            "https://learn.microsoft.com/graph",
            "https://learn.microsoft.com/microsoft-365",
            "https://learn.microsoft.com/office",
            "https://learn.microsoft.com/powershell",
            "https://learn.microsoft.com/sql",
            "https://learn.microsoft.com/surface",
            "https://learn.microsoft.com/system-center",
            "https://learn.microsoft.com/visualstudio",
            "https://learn.microsoft.com/windows",
            "https://learn.microsoft.com/maui"
    };

    static async Task Main()
    {
        Console.WriteLine("Application started.");
        Console.WriteLine("Press the ENTER key to cancel...\n");

        Task cancelTask = Task.Run(() =>
        {
            while (Console.ReadKey().Key != ConsoleKey.Enter)
            {
                Console.WriteLine("Press the ENTER key to cancel...");
            }

            Console.WriteLine("\nENTER key pressed: cancelling downloads.\n");
            s_cts.Cancel();
        });

        Task sumPageSizesTask = SumPageSizesAsync();

        Task finishedTask = await Task.WhenAny(new[] { cancelTask, sumPageSizesTask });
        if (finishedTask == cancelTask)
        {
            // wait for the cancellation to take place:
            try
            {
                await sumPageSizesTask;
                Console.WriteLine("Download task completed before cancel request was processed.");
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Download task has been cancelled.");
            }
        }

        Console.WriteLine("Application ending.");
    }

    static async Task SumPageSizesAsync()
    {
        var stopwatch = Stopwatch.StartNew();

        int total = 0;
        foreach (string url in s_urlList)
        {
            int contentLength = await ProcessUrlAsync(url, s_client, s_cts.Token);
            total += contentLength;
        }

        stopwatch.Stop();

        Console.WriteLine($"\nTotal bytes returned:  {total:#,#}");
        Console.WriteLine($"Elapsed time:          {stopwatch.Elapsed}\n");
    }

    static async Task<int> ProcessUrlAsync(string url, HttpClient client, CancellationToken token)
    {
        HttpResponseMessage response = await client.GetAsync(url, token);
        byte[] content = await response.Content.ReadAsByteArrayAsync(token);
        Console.WriteLine($"{url,-60} {content.Length,10:#,#}");

        return content.Length;
    }
}

Lihat juga

Langkah berikutnya