CSharp(C#)语言_高级篇(异步编程)【划重点咯】

什么是异步

  启动程序时,系统会在内存中创建一个新的进程。进程是构成运行程序的资源的集合。这些资源包括虚地址空间、文件句柄和许多其他程序运行所需的东西。
 在进程内部,系统创建了一个称为线程的内核(kernel)对象,它代表了真正执行的程序。(线程是“执行线程”的简称。)一旦进程建立,系统会在Nain方法的第一行语句处就开始线程的执行

关于线程,需要了解以下知识点:

  • 默认情况下,一个进程只包含一个线程,从程序的开始一直执行到结束
  • 线程可以派生其他线程,因此在任意时刻,一个进程都可能包含不同状态的多个线程,来执行程序的不同部分
  • 如果一个进程拥有多个线程,它们将共享进程的资源
  • 系统为处理器执行所规划的单元是线程,不是进程

  在异步程序中,程序代码不需要按照编写时的顺序严格执行。有时需要在一个新的线程中运行一部分代码,有时无需创建新的线程,但为了更好地利用单个线程的能力,需要改变代码的执行顺序

  • 在C#5.0中引入的一个用来构建异步方法的新特性——async/await
  • .NET框架的特性——BackgroundWorker类 和 .NET任务并行库(没有嵌入C#中)

async/await特性的结构

  如果一个程序调用某个方法,等待其执行所有处理后才继续执行,我们就称这样的方法是同步的。这是默认的形式
  相反,异步的方法在处理完成之前就返回到调用方法。C#的async/await特性可以创建并使用异步方法。该特性由三个部分组成
async/await特性的整体结构

  • 调用方法(calling method):该方法调用异步方法,然后在异步方法(可能在相同的线程,也可能在不同的线程)执行其任务的时候继续执行
  • 异步(async)方法:该方法异步执行其工作,然后立即返回到调用方法
  • await表达式:用于异步方法内部,指明需要异步执行的任务。一个异步方法可以包含任意多个await表达式,不过如果一个都不包含的话编译器会发出警告

什么是异步方法

在语法上,异步方法具有如下特征:
异步方法特征

  • 方法头中包含async方法修饰符
  • 包含一个或多个await表达式,表示可以异步完成的任务
  • 必须具备以下三种返回类型。第二种(Task)和第三种(Task)的返回对象表示将在未来完成的工作,调用方法和异步方法可以继续执行
      ■ void
      ■ Task
      ■ Task<T>
  • 异步方法的参数可以为任意类型任意数量,但不能为outref参数
  • 按照约定,异步方法的名称应该以Async为后缀
  • 除了方法以外,Lambda表达式和匿名方法也可以作为异步对象

注意:

  • 异步方法在方法头中必须包含async关键字,且必须出现在返回类型之前
  • 该修饰符只是标识该方法包含一个或多个await表达式。也就是说,它本身并不能创建任何异步操作
  • async关键字是一个上下文关键字,也就是说除了作为方法修饰符(或Lambda表达式修饰符、匿名方法修饰符)之外,async还可用作标识符

异步方法实例:(异步方法三种返回类型)

				//使用返回 Task<T> 对象的异步方法
using System;
using System.Threading.Tasks;

class Program
{
	static void Main() 
	{
		Task<int> value = DoAsyncStuff.CalculateSumAsync( 5, 6 );
		// 处理其他事情 ...
		Console.WriteLine( "Value: {0} ", value.Result );
	}
}

static class DoAsyncStuff
{
	public static async Task<int> CalculateSumAsync( int i1, int i2 )
	{
		int sum = await Task.Run(() => GetSum( i1, i2 ));
		return sum;
	}
	
	private static int GetSum( int i1, int i2 ) 
	{ 
		return i1 + i2; 
	}
}
				//使用返回 Task 对象的异步方法
using System;
using System.Threading.Tasks;

class Program
{
	static void Main()
	{
		Task someTask = DoAsyncStuff.CalculateSumAsync(5, 6);
		// 处理其他事情
		someTask.Wait();
		Console.WriteLine( "Async stuff is done" );
	}
}

static class DoAsyncStuff
{
	public static async Task CalculateSumAsync( int i1, int i2)
	{
		int value = await Task.Run(() => GetSum( i1, i2 ));
		Console.MriteLine("Value: {0}", value );
	}
	
	private static int GetSum( int i1, int i2) 
	{
		return i1 + i2;
	}
}
				//使用返回 "调用并忘记(void)" 的异步方法
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
	static void Main()
	{
		DoAsyncStuff.CalculateSumAsync(5, 6);
		// 处理其他事情
		Thread.Sleep( 200 );
		Console.WriteLine( "Program Exiting" );
	}
}

static class DoAsyncStuff
{
	public static async void CalculateSumAsync(int i1, int i2)
	{
		int value = await Task.Run(() => GetSum( i1, i2 ));
		Console.MriteLine( "Value:(0) ", value );
	}
	
	private static int GetSum(int i1, int i2)
	{ 
		return i1 + i2;
	}
)

异步方法的控制流

  • 第一个await表达式之前的部分:从方法开头到第一个await表达式之间的所有代码。这一部分应该只包含少量且无需长时间处理的代码
  • await表达式:表示将被异步执行的任务
  • 后续部分:在await表达式之后出现的方法中的其余代码。包括其执行环境,如所在线程信息、目前作用域内的变量值,以及当await表达式完成后要重新执行所需的其他信息
    异步方法代码域
      它从第一个await表达式之前的代码开始,正常执行(同步地)直到遇见第一个await。这一区域实际上在第一个await表达式处结束,此时await任务还没有完成(大多数情况下如此)。当await任务完成时,方法将继续同步执行。如果还有其他await,就重复上述过程
      当达到await表达式时,异步方法将控制返回到调用方法。如果方法的返回类型为Task或Task<T>类型,将创建一个Task对象,表示需异步完成的任务和后续,然后将该Task返回到调用方法

  目前有两个控制流:异步方法内的和调用方法内的。异步方法内的代码完成以下工作

  • 异步执行await表达式的空闲任务。
  • await表达式完成时,执行后续部分。后续部分本身也可能包含其他await表达式,这些表达式也将按照相同的方式处理,即异步执行await表达式,然后执行后续部分
  • 当后续部分遇到return语句或到达方法末尾时,将:
    • 如果方法返回类型为void,控制流将退出
    • 如果方法返回类型为Task,后续部分设置Task的属性并退出。如果返回类型为Task<T>,后续部分还将设置Task对象的Result属性

  同时,调用方法中的代码将继续其进程,从异步方法获取Task对象。当需要其实际值时,就引用Task对象的Result属性。届时,如果异步方法设置了该属性,调用方法就能获得该值并继续。否则,将暂停并等待该属性被设置,然后再继续执行
异步方法控制流

await 表达式

  await表达式指定了一个异步执行的任务。其语法如下所示,由await关键字和一个空闲对象(称为任务)组成。这个任务可能是一个Task类型的对象,也可能不是。默认情况下,这个任务在当前线程异步运行

取消一个异步操作

一些.NET异步方法允许你请求终止执行。同样也可以在自己的异步方法中加入这些特性
System.Threading.Tasks命名空间中有两个类是为此目的而设计的:CancellationTokenCancellationTokenSource

  • CancellationToken对象包含一个任务是否应被取消的信息
  • 拥有CancellationToken对象的任务需要定期检查其令牌(token)状态。如果CancellationToken对象的IsCancellationRequested属性为true,任务需停止其操作并返回
  • CancellationToken是不可逆的,并且只能使用一次。也就是说,一旦IsCancellationRequested属性被设置为true,就不能更改了
  • CancellationTokenSource对象创建可分配给不同任务的CancellationToken对象。任何持有CancellationTokenSource的对象都可以调用其Cancel方法,这会将CancellationTokenIsCancellationRequested属性设置为true

GUI程序中的异步操作

异步编程对于GUI程序非常重要,篇幅限制,不再赘述

使用异步的Lambda表达式

这里使用 WPF 程序来演示异步的Lambda表达式的用法

//前端界面xaml代码
<Window x:Class="AsyncLambda.Mainwindow"
		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		Title="Async Lambda" Height="115" Width="150">

	<StackPanel>
		<TextBlock Name="workStartedTextBlock" Margin="10,10"/>
		<Button Name="startWorkButton" Width="100" Margin="4"  Content="Start Work"/>
	</StackPanel>
</Window>
// 后台代码
using System.Threading.Tasks;
using System.Windows;

namespace AsyncLambda
{
	public partial class MainWindow:Window
	{
		public MainWindow()
		{
			InitializeComponent();
									 // 异步Lambda表达式
			startHorkButton.Click += async ( sender, e)=>
			{
				SetGuiValues( false, "Work Started");
				await DoSomeWork();
				SetGuiValues( true, "Hork Finished");
			};
		}
		
		private void SetGuiValues(bool buttonEnabled, string status)
		{
			starthorkButton.IsEnabled = buttonEnabled;
			workStartedTextBlock.Text = status;
		}
	
		private Task DoSomework()
		{
			return Task.Delay( 2500 );
		}
	}
}

结果
ps:
就此结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑夜中的潜行者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值