异步编程(三)

CancellationToken结构体:

有时需要提前终止任务,比如:请求超时、用户取消请求

很多异步方法都有CancellationToken参数,用于获得提前终止的信号

  • None:空
  • bool IsCancellationRequested:是否取消
  • Register(Action callback):注册取消监听
  • ThrowlfCancellationRequested():如果任务被取消,执行到这句话就抛异常

CancellationTokenSource:

  • CancelAfter():超时后发出取消信号
  • Cancel():发出取消信号
  • CancellationToken Token:用于创建CancellationToken结构体
//用户敲击按键取消异步操作
CancellationTokenSource tokens = new CancellationTokenSource();
CancellationToken token = tokens.Token;
DownloadlAsync3("https://www.baidu.com", 100, token);
while (Console.ReadLine() != "q")
{

}
tokens.Cancel();
Console.ReadLine();

//超时后取消异步操作
static async Task Main1(string[] args)
{
    CancellationTokenSource tokens = new CancellationTokenSource();
    //3秒后超时
    tokens.CancelAfter(3000);
    CancellationToken token = tokens.Token;
    await DownloadlAsync3("https://www.baidu.com", 100, token);
}

//不取消异步操作代码
static async Task DownloadlAsync(string url, int n)
{
    using (HttpClient httpClient = new HttpClient())
    {
        for (int i = 0; i < n; i++)
        {

            string html = await httpClient.GetStringAsync(url);
            Console.WriteLine($"{DateTime.Now}:{html}");
        }
    }
}

//两种手动取消异步操作代码的方式
static async Task DownloadlAsync2(string url, int n, CancellationToken token)
{
    using (HttpClient httpClient = new HttpClient())
    {
        for (int i = 0; i < n; i++)
        {

            string html = await httpClient.GetStringAsync(url);
            Console.WriteLine($"{DateTime.Now}:{html}");
            //方式一:通过IsCancellationRequested判断是否超时,取消异步操作
            /*
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("请求被取消");
                break;
            }
            */
            //方式二:超时抛出异常,取消异步操作
            token.ThrowIfCancellationRequested();
        }
    }
}

//GetAsync自动取消异步操作
static async Task DownloadlAsync3(string url, int n, CancellationToken token)
{
    using (HttpClient httpClient = new HttpClient())
    {
        for (int i = 0; i < n; i++)
        {
            //返回Task<HttpResponseMessage>
            var resp = await httpClient.GetAsync(url, token);
            //将HTTP内容序列化成字符串,异步操作
            string html = await resp.Content.ReadAsStringAsync();
            Console.WriteLine($"{DateTime.Now}:{html}");
        }
    }
}

ASP.NET Core开发中,一般不需要自己处理CancellationToken、CancellationTokenSource,只要做到“能转发CancellationToken就转发”即可。ASP.NET Core会对于用户请求中断进行处理。

Web开发中CancellationToken的使用:

Web开发中,网页处理时间较长时,用户关闭浏览器或访问其他网页时,如果该网页的请求在服务器端没有完成,则服务器会自动终止访问请求,以此来节省服务器资源

//在.NET Core MVC中,控制器增加一个CancellationToken参数,该参数由.NET框架进行赋值
//当网页关闭或刷新时,.NET框架会自动传递信号取消异步操作
public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
    await DownloadlAsync("https://www.baidu.com", 10, cancellationToken);
    return View();
}

static async Task DownloadlAsync(string url, int n, CancellationToken cancellationToken)
{
    using (HttpClient httpClient = new HttpClient())
    {
        for (int i = 0; i < n; i++)
        {
            var resp = await httpClient.GetAsync(url, cancellationToken);
            string html = await resp.Content.ReadAsStringAsync();
            Debug.WriteLine(html);
        }
    }
}

Task类中 WhenAll与WhenAny的使用

Task.WhenAny(Task[]):任何一个Task完成,Task就完成

Task.WhenAll(Task[]):所有Task完成,Task才完成。用于多个任务执行结束,但是不在乎它们的执行顺序

FromResult():创建普通数值的Task对象

static async Task Main(string[] args)
{
    //异步方式读出文件信息,
    Task<string> t1 = File.ReadAllTextAsync(@"E:\temp\a.txt");
    Task<string> t2 = File.ReadAllTextAsync(@"E:\temp\b.txt");
    Task<string> t3 = File.ReadAllTextAsync(@"E:\temp\c.txt");
    //等待三个任务结束
    string[] str = await Task.WhenAll(t1, t2, t3);
    Console.WriteLine(str[0]);
    Console.WriteLine(str[1]);
    Console.WriteLine(str[2]);
}
练习: 计算应该文件夹下,所有文本文件的单词个数汇总
static async Task Main(string[] args)
{
    //获取文件夹下所有文件路径
    string[] files = Directory.GetFiles(@"E:\temp");
    //创建数组存储每个文件字符数量
    Task<int>[] countTasks = new Task<int>[files.Length];
    for (int i = 0; i < files.Length; i++)
    {
        string filename = files[i];
        Task<int> t = ReadCharsCount(filename);
        countTasks[i] = t;
    }
    int[] counts = await Task.WhenAll(countTasks);
    int c = counts.Sum();
    Console.WriteLine(c);

}

/// <summary>
/// 文件共有多少个字符
/// </summary>
/// <param name="filname">文件路径</param>
/// <returns>字符数量</returns>
static async Task<int> ReadCharsCount(string filname)
{
    string s = await File.ReadAllTextAsync(filname);
    return s.Length;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值