何为异步,先说同步,比如我们界面上有个按钮,需要做一个复杂的运算,那么UI主线程就会一直等待这个方法运算结束,同时主界面卡住,异步就是相对同步来说的,异步是不阻塞主线程,同样去执行这个方法,下面用一个例子来体会。
<Button Content="同步方法" HorizontalAlignment="Left" Margin="142,116,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<Button Content="异步方法" HorizontalAlignment="Left" Margin="307,116,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
private void Button_Click(object sender, RoutedEventArgs e)
{
FunctionNormal();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
FunctionAsync();
}
public void FunctionNormal()
{
for (int i = 0; i < 10000; i++)
{
Console.WriteLine(i);
}
}
public async void FunctionAsync()
{
await Task.Run(() =>
{
for (int i = 0; i < 10000; i++)
{
Console.WriteLine(i);
}
});
}
当点击同步按钮,执行方法后,就没有办法拖动窗体或者做操作了,点击异步方法就可以继续拖动窗体或者做其他操作。
通过上面那个例子,很清楚的看到异步就i是通过Task来完成的,Task就是表示没有返回值的任务,如果有返回值的就可以使用Task<TResult>.
在正式接触任务之前,需要做个简单的知识储备,就是Lambda表达式,对于一些匿名函数需要封装在委托内时,我们就可以使用Lambda表达式了,也很简单,()=>{};前面小括号是参数,后面大括号是方法内容。
接着需要储备的就是.NET内置的两个委托,Action和Func,Action委托是不带返回值的,Fun是带返回值的,需要注意的是Func最后一个参数就是委托的返回值。
现在正式接触异步编程,两个重要的关键字,Async和await,Async是专门修饰方法的,当一个方法被Async修饰后,就表示这是一个异步方法,他的返回值就必须是Void,Task,Task<TResult>,但是并不是说加了Async之后方法一定就会异步执行,需要在异步方法的内部使用await关键字。
await关键字表示等待异步执行的结果,所以这个执行必须要有返回值,并且返回值必须要是Task或Task<TResult>,创建任务也非常简单,前面的例子已经说明了。
比如,我们已经有了线程池,也可以解决界面卡住的现象,为什么还需要Task呢,那么就要知道ThreadPool的缺点,首先,无法取消线程池任务,没办法知道任务执行的状态,也不知道任务执行的进度,在Task里面,则都有提供了。
<Button Content="开始执行任务" HorizontalAlignment="Left" Margin="152,37,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<TextBlock Name="tb1" HorizontalAlignment="Left" Margin="152,114,0,0" TextWrapping="Wrap" Text="显示结果" VerticalAlignment="Top"/>
<Button Content="取消任务" HorizontalAlignment="Left" Margin="280,23,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
private CancellationTokenSource cts = new CancellationTokenSource();
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
tb1.Text += await FunctionAsync("a", cts.Token);
}
public async Task<string> FunctionAsync(string s, CancellationToken ct)
{
await Task.Run(() =>
{
for (int i = 0; i < 50000000; i++)
{
Thread.Sleep(1000);
if (ct.IsCancellationRequested)
break;
s += "haha";
}
});
return s;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
也很清晰明了,就是通过CancellationTokenSource,来实现的,同样的道理可以监控任务的状态和进度,这个也没有难度,用的时候去查一下就可以了。