前言
本节将介绍3中不同的异步编程:异步模式、基于事件的异步模式和基于任务的异步模式
1.异步模式
通过委托来实现异步(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法),使用回调函数。注:运行在.NET FrameWork框架下
1.1异步方法--传1个参数
class Program
{
static void Main(string[] args)
{
//通过委托来实现异步编程的(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法)
string i = "参数";
Console.WriteLine("调用异步方法前");
PostAsync(i);
Console.WriteLine("调用异步方法后");
Console.ReadKey();
}
delegate void AsyncFoo(string i);//定义委托
private static void PostAsync(object i)
{
AsyncFoo caller = Myfunc;//声明委托
caller.BeginInvoke(i.ToString(), FooCallBack, caller);//绑定委托
}
//回调方法
private static void FooCallBack(IAsyncResult ar)
{
var caller = (AsyncFoo)ar.AsyncState;
caller.EndInvoke(ar);
}
/// <summary>
/// 执行业务逻辑的方法
/// </summary>
/// <param name="i">调用异步时传过来的参数</param>
private static void Myfunc(string i)
{
Console.WriteLine("通过委托来实现异步编程的");
}
}
运行结果:
1.2 异步方法--传2个或多个参数
class Program
{
static void Main(string[] args)
{
//通过委托来实现异步编程的(在委托类型中定义了BeginInvoke()和EndInvoke()两个方法)
Console.WriteLine("调用异步方法前");
PostAsync("参数1", "参数2");
Console.WriteLine("调用异步方法后");
Console.ReadKey();
}
delegate void AsyncFoo(string i, string p);//定义委托
private static void PostAsync(string i, string p)
{
AsyncFoo caller = Myfunc;//声明委托
//FooCallBack,caller为额外的参数
caller.BeginInvoke(i, p, FooCallBack, caller);//绑定委托
}
/// <summary>
/// 回调函数
/// </summary>
/// <param name="ar">委托执行完毕后EndInvoke的返回值</param>
private static void FooCallBack(IAsyncResult ar)
{
var caller = (AsyncFoo)ar.AsyncState;
caller.EndInvoke(ar);
}
/// <summary>
/// 执行业务逻辑的方法
/// </summary>
/// <param name="i">参数1</param>
/// <param name="p">参数2</param>
private static void Myfunc(string i, string p)
{
Console.WriteLine(i);
Console.WriteLine(p);
}
}
运行结果:
2. 基于事件的异步模式
.NET2.0之后推出了基于事件的异步模式,更便于处理UI更新。设计思路是在同步方法名称的后面加上了一个“Async”的后缀。这个方法在此就先不详解了,看下看更加方便的异步技术
3. 基于任务的异步模式
3.1 task
.NET4.0的新特性,便于基于任务的编程,完成多线程控制的目标。
class Program
{
static void Main(string[] args)
{
Console.WriteLine("主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
//Task方式一
Task task1 = new Task(() => TaskFunc1());
task1.Start();
//Task方式二
var result = Task.Run<string>(() => { return TaskFunc2(); });
Console.WriteLine(result.Result);
Console.ReadKey();
}
private static void TaskFunc1()
{
Task.Delay(1000).Wait();
Console.WriteLine("Task方式一开启的线程ID:" + Thread.CurrentThread.ManagedThreadId);
}
private static string TaskFunc2()
{
return "Task方式二开启的线程ID:" + Thread.CurrentThread.ManagedThreadId;
}
}
运行结果:
3.2 await async——使用单个异步方法
.NET4.5的新特性,该模式定义了一个带"Async"后缀的方法,并返回一个Task<string>类型。
3.2.1 控制台示例
class Program
{
static void Main(string[] args)
{
Console.WriteLine("主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
var result1 = AsyncFunc1();//调用异步方法
Console.WriteLine(result1.Result);
Console.ReadKey();
}
/// <summary>
/// 创建任务
/// </summary>
/// <returns></returns>
private static async Task<string> AsyncFunc1()
{
return await Task.Run(() =>
{
Task.Delay(1000).Wait();
Console.WriteLine("await/async线程ID: {0}", Thread.CurrentThread.ManagedThreadId);
return "这是返回值";
});
}
}
运行结果:
3.2.2 WinForm窗体示例1
private void button1_Click(object sender, EventArgs e)
{
Dog dog = new Dog();
Task task = dog.DoSomthingAsync().ContinueWith(OnDoSomthingIsComplete);
}
///
///任务完成后要执行的方法,更新UI
///
private void OnDoSomthingIsComplete(Task t)
{
Action action = () => {
textBox1.Text = "任务完成后显示这段文字到UI控件";
};
textBox1.Invoke(action);
}
/// <summary>
/// Dog类
/// </summary>
public class Dog
{
public Task DoSomthingAsync()
{
Task task = Task.Run(() => {
Console.WriteLine("后台任务开始运行");
Thread.Sleep(5000);
Console.WriteLine("后台任务运行结束");
});
return task;
}
}
运行结果:
3.2.3 WinForm窗体示例2
private async void button1_Click(object sender, EventArgs e)
{
checkBox1.Checked = await MoveArm();
}
/// <summary>
/// 创建任务
/// </summary>
/// <returns></returns>
private async Task<bool> MoveArm()
{
return await Task<bool>.Run(async() =>
{
await Task.Delay(5000);//异步 等待Task完成执行过程
return true;
});
}
/************************或者*************************/
/// <summary>
/// 创建任务
/// </summary>
/// <returns></returns>
private async Task<bool> MoveArm()
{
return await Task<bool>.Run(() =>
{
Task.Delay(5000).Wait();//等待Task完成执行过程
return true;
});
}
运行结果:
3.3 await async——使用多个异步方法
3.3.1 如果一个异步方法依赖于另外一个异步方法,则按顺序调用异步方法
这时候await关键字就非常有用,每个异步方法都得使用await关键字。
3.3.2 如果一个异步方法不依赖与另外一个异步方法,使用组合器
这时候每个异步方法可以不使用await关键字,而是把每个异步方法的返回结果赋值给Task变量,然后使用Task的WhenAll组合器或WhenAny组合器,这样运行可以更快。
其中,WhenAll方法返回Task,是在所有的传入方法的任务都完成了才会返回Task。从WhenAny方法返回的Task,是在其中一个传入方法的任务完成了就会返回Task。