首页 > 编程语言 >.NET 异步编程模式 (四)-TAP

.NET 异步编程模式 (四)-TAP

时间:2022-08-18 13:22:44浏览次数:61  
标签:异步 Task TAP cts await async NET public

TAP 是基于任务的异步模式,在 .NET Framework 4 中引入。TAP取代了 APM 和EAP,是推荐的异步编程模式。

async / await

async 和 await 是为异步编程提供的语法糖,方便我们快捷编写异步代码。关键字 async 作用仅仅是为了能够使用 await 关键字以及怎么处理返回值。await 关键字可以想象成 asynchronous wait,在awaitable 完成之前,异步方法会等待,但线程不会堵塞。

public async Task DoSomethingAsync()
{
    // For this example, we`re just going to (aynchronously) wait 100ms.
    await Task.Delay(100);
}

对于调用方法,await 声明了一个挂起点,等异步方法结束后会捕获当前上下文继续执行后续代码。、

awaitable

await 就像是一元操作符,接收一个参数 - awaitable. Task<T> 和 Task 都是这样的类型。

public async Task NewStuffAsync()
{
    // Use await and have fun with the new stuff.
    await ...
}
public Task MyOldTaskParallelLibraryCode()
{
    // Note that this is not an async method, so we can`t use await in here.
    ...
}
public async Task ComposeAsync()
{
    // We can await Tasks, regardless of where they come from.
    await NewStuffAsync();
    await MyOldTaskParallelLibraryCode();
}

Task.Yield()

await Task.Yield() 方法来强制异步完成方法,可以让我们更好的控制异步方法的执行。如果当前任务很耗时,并且优先级比较低,可以考虑在方法开始的时候加上 await Task.Yield() ,让系统去调度其他更需要的任务,稍后再来完成该耗时任务。

static async Task Process()
{
    await Task.Yield();

    var tcs = new TaskCompletionSource<bool>();

    Task.Run(() =>
    {
        Thread.Sleep(1000);
        tcs.SetResult(true);
    });

    tcs.Task.Wait();
}

我不着急,我到后面从新排队去,你先去处理其他任务吧。其实是利用 await 实现线程的切换

Task.ConfigureAwait

默认情况,异步方法结束后会捕获和回复当前上下文。如果你不关系延续上下文,可以使用 Task.ConfigureAwait 指示不要回复而是继续执行等待的任务。

await someTask.ConfigureAwait(continueOnCapturedContext:false);

CancellationTokenSource

从 .NET Framework 4 开始,TAP 方法支持取消操作。

var cts = new CancellationTokenSource();
string result = await DownloadStringTaskAsync(url, cts.Token);
… // at some point later, potentially on another thread
cts.Cancel();

// 取消多个异步调用
var cts = new CancellationTokenSource();
IList<string> results = await Task.WhenAll(from url in urls select DownloadStringTaskAsync(url, cts.Token));
// at some point later, potentially on another thread
…
cts.Cancel();

Progress

通过 Progress 可以监控异步方法的执行进度。

private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
    btnDownload.IsEnabled = false;
    try
    {
        txtResult.Text = await DownloadStringTaskAsync(txtUrl.Text,
            new Progress<int>(p => pbDownloadProgress.Value = p));
    }
    finally { btnDownload.IsEnabled = true; }
}

Task.Run

Task.Run() 方法可以很方便的将耗时任务放到线程池上执行。

public async void button1_Click(object sender, EventArgs e)
{
    // 默认恢复上下文
    textBox1.Text = await Task.Run(() =>
    {
        // … do compute-bound work here
        return answer;
    });
}

public async void button1_Click(object sender, EventArgs e)
{
    // 内部使用 await
    pictureBox1.Image = await Task.Run(async() =>
    {
        using(Bitmap bmp1 = await DownloadFirstImageAsync())
        using(Bitmap bmp2 = await DownloadSecondImageAsync())
        return Mashup(bmp1, bmp2);
    });
}

Task.FromResult

Task.FromResult 用来创建一个带返回值的,已完成的 Task。

public Task<int> GetValueAsync(string key)
{
    int cachedValue;
    return TryGetCachedValue(out cachedValue) ?
        Task.FromResult(cachedValue) :              // 如果本地有缓存,直接以同步的方式获取(但返回的是异步结果)
        GetValueAsyncInternal();                    // 如果本地没有key对应的缓存,则异步从远端获取
}
// 异步方法从远端获取缓存
private async Task<int> GetValueAsyncInternal(string key)
{
    …
}

Task.WhenAll

异步等待 一组异步操作的完成。

Task [] asyncOps = (from addr in addrs select SendMailAsync(addr)).ToArray();
try
{
    await Task.WhenAll(asyncOps);
}
catch(Exception exc)
{
    foreach(Task faulted in asyncOps.Where(t => t.IsFaulted))
    {
        … // work with faulted and faulted.Exception
    }
}

Task.WhenAny

一组异步操作中,第一个异步操作完成时返回。

  1. 可以同时进行多个相同的异步操作,选择最快完成的那个
// 从多个行情源处获取行情,使用最快的那个
var cts = new CancellationTokenSource();
var recommendations = new List<Task<bool>>()
{
    GetBuyRecommendation1Async(symbol, cts.Token),
    GetBuyRecommendation2Async(symbol, cts.Token),
    GetBuyRecommendation3Async(symbol, cts.Token)
};

Task<bool> recommendation = await Task.WhenAny(recommendations);
cts.Cancel(); // 取消剩余任务
if (await recommendation) BuyStock(symbol);
  1. 多个任务交叉进行(每完成一个就处理一个)
List<Task<Bitmap>> imageTasks =
    (from imageUrl in urls select GetBitmapAsync(imageUrl)
         .ContinueWith(t => ConvertImage(t.Result)).ToList();
while(imageTasks.Count > 0)
{
    try
    {
        Task<Bitmap> imageTask = await Task.WhenAny(imageTasks);
        imageTasks.Remove(imageTask);

        Bitmap image = await imageTask;
        panel.AddImage(image);
    }
    catch{}
}

Task.Delay

在异步方法中暂定一段时间。 可以和 Task.WhenAny ,Task.WhenAll 结合使用以实现超时处理。

public async void btnDownload_Click(object sender, EventArgs e)
{
    btnDownload.Enabled = false;
    try
    {
        Task<Bitmap> download = GetBitmapAsync(url);
        if (download == await Task.WhenAny(download, Task.Delay(3000)))
        {
            Bitmap bmp = await download;
            pictureBox.Image = bmp;
            status.Text = "Downloaded";
        }
        else
        {
            pictureBox.Image = null;
            status.Text = "Timed out";
            var ignored = download.ContinueWith(
                t => Trace("Task finally completed"));
        }
    }
    finally { btnDownload.Enabled = true; }
}

公众号 - 希夏普

标签:异步,Task,TAP,cts,await,async,NET,public
From: https://www.cnblogs.com/jqwang/p/16598358.html

相关文章

  • javascript 执行机制(同步、异步、微任务、宏任务)
    一、关于javascriptJS是一门单线程语言,这意味着所有的任务都需要排队,前一个任务结束才会执行后一个任务如果前一个任务耗时很长,后一个任务就不得不一直等着。这样所导致的......
  • InetAddress inetAddress 常用方法
    javaSE进阶之InetAddress类的域名解析与代码实例2021-08-1909:491.通讯要素1:IP和端口号IP地址:InetAddress唯一的标识Internet上的计算机本地回环地址(hostAddress......
  • 在asp.net中开启后台任务
    开始后台任务一般是Task.Run()查在asp.net时进行可能会被回收,导致Task中断。在Asp,net中有专门的后台任务函数: System.Web.Hosting.HostingEnvironment.QueueBackgroun......
  • 【前端基础】(二)promise异步编排
    ☆promise异步编排javascript众所周知只能支持单线程,因此各种网络请求必须异步发送,导致可能会出现很多问题,比如如下我们有三个文件,现在要求进行如下请求:①查出当前用户......
  • .Net core 利用Npoi.Mapper 生成Excel
    1.NuGet添加Npoi.Mapper引用   2.初始化privatevoidbutton1_Click(objectsender,EventArgse){//数据导出测试......
  • netty系列之:netty实现http2中的流控制
    目录简介http2中的流控制netty对http2流控制的封装Http2FlowControllerHttp2LocalFlowControllerHttp2RemoteFlowController流控制的使用总结 简介HTTP......
  • .net 6 中使用Log4Net 方式 winform
    1.直接添加一个帮助类usinglog4net;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;//文件......
  • Kubernetes学习笔记(十一):Node Selectors & Affinity
    NodeSelectorspod-definition.ymlspec:nodeSelector:size:Large##生效前需要先标记nodekubectllabelnodes<node-name><label-key>=<label-value>:......
  • Kubernetes-概述
    Kubernetes概述Kubernetes概述Kubernetes是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes拥有一个庞大且快速......
  • Kubernetes学习笔记(十):Taints and Tolerations
    Taints-Node:kubectltaintnodesnode-namekey=value:taint-effecttaint-effect:NoSchedule|PreferNoSchedule|NoExecuteNoExecute:新Pod不会部署,已存在的......