.NET 异步编程模式 (四)

您所在的位置:网站首页 risingwaves .NET 异步编程模式 (四)

.NET 异步编程模式 (四)

#.NET 异步编程模式 (四)| 来源: 网络整理| 查看: 265

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

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

可以同时进行多个相同的异步操作,选择最快完成的那个 // 从多个行情源处获取行情,使用最快的那个 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); 多个任务交叉进行(每完成一个就处理一个) 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.Delay

在异步方法中暂定一段时间。 可以和 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; } } 公众号 - 希夏普


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3