介绍一种基于任务的异步模式TAP

描述

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

异步/等待 

async 和 是为异步编程的语法,方便我们在之前编写异步代码,有办法会等待,但不会阻止。 

public async Task DoSomethingAsync() 

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


对于调用的方法,等一个方法结束后会显示,等今天今天继续执行显示代码。、 

等待的 

await 就像是一元操作符,接收一个参数 -  awaitable。Task 和 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() 异步强制完成方法,可以来让我们的异步方法执行。 Yield() ,让其他调度需要的任务,随后完成该任务更替。 

static async Task Process() 

   await Task.Yield(); 

   var tcs = new TaskCompletionSource(); 

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

   tcs.Task.Wait(); 


我不着急,我到后面再去其他任务去,你先去处理吧。其实是利用等待线程的切换。 

任务.配置等待 

在这种情况下,某种方法结束后可以继续执行当前的回复任务。 

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 results = await Task.WhenAll(from url in urls select DownloadStringTaskAsync(url, cts.Token)); 
// at some point later, potentially on another thread 
… 
cts.Cancel(); 

进步 

通过进度可以远程监控方法的执行。 

private async void btnDownload_Click(object sender, RoutedEventArgs e) 

   btnDownload.IsEnabled = false; 
   try 
   { 
       txtResult.Text = await DownloadStringTaskAsync(txtUrl.Text, 
           new Progress(p => pbDownloadProgress.Value = p)); 
   } 
   finally { btnDownload.IsEnabled = true; } 


任务运行 

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); 
   }); 

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

public Task GetValueAsync(string key) 

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

// 异步方法从远端获取缓存 
private async Task GetValueAsyncInternal(string key) 

   … 


任务.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>() 

   GetBuyRecommendation1Async(symbol, cts.Token), 
   GetBuyRecommendation2Async(symbol, cts.Token), 
   GetBuyRecommendation3Async(symbol, cts.Token) 
}; 

Task recommendation = await Task.WhenAny(recommendations); 
cts.Cancel(); // 取消剩余任务 
if (await recommendation) BuyStock(symbol); 
1.多个任务交叉进行(每完成一个就处理一个) 

List> imageTasks = 
   (from imageUrl in urls select GetBitmapAsync(imageUrl) 
        .ContinueWith(t => ConvertImage(t.Result)).ToList(); 
while(imageTasks.Count > 0) 

   try 
   { 
       Task imageTask = await Task.WhenAny(imageTasks); 
       imageTasks.Remove(imageTask); 

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


任务延迟 

在任意方法中确定任务。可以和 Task.WhenAny ,Task.WhenAll 结合使用以暂态调用处理。 

public async void btnDownload_Click(object sender, EventArgs e) 

   btnDownload.Enabled = false; 
   try 
   { 
       Task 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; } 




审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分