在最近的一个项目中,需要一个线程(Thread)不停地检测图片数据,并对数据进行处理,为了保证运行效率,需要在合适的时间对线程挂起和唤醒,所以使用Thread.Suspen和Thread.Resume,在vs中会提示这两个函数已过时,而且使用时Suspen由于不会释放所占用的锁,造成死锁(在IDE中运行时会出现死锁的情况,单独运行exe未出现,但是这样使用不安全),所以只能想其他办法。发现.net 4.5中的Async和Await可以很好的实现所需要的功能,而且使用起来也很方便。
Async,Await 异步编程(MSDN,很详细)
async
修饰符可将方法、lambda 表达式或匿名方法指定为异步。
如果对方法或表达式使用此修饰符,则其称为异步方法。也就是使用Async修饰的方法,lambda表达式和匿名方法都是异步方法,比如(测试程序基于WPF):
public MainWindow() { InitializeComponent(); CirleAsync(); } public async Task<int> CirleAsync() { int i = 5; while(i > 0) { await Task.Delay(1000); Console.WriteLine("{0}\n", i); i--; } return i; }
一个死循环的异步方法:
public async Task TestMethod() { while (true) { } } public async Task CircleForever() { await TestMethod(); }
对话框的构造函数中调用该方法:
public MainWindow() { InitializeComponent(); //CirleAsync(); CircleForever(); MessageBox.Show("上面是异步方法,我应该被弹出"); //tt(); }
根据对正常的对异步编程的理解,CircleForever不应该会阻塞主进程,MessageBox应该会立即弹出,然而运行时却发现,Message没有弹出来,说明程序一直在死循环中,WHY!!!,其实这是对Async和Await的错误理解,认为只要有async修饰的方法就是异步方法,真正实现异步的是async修饰方法中的Task类,async只是做一个标记,告诉编译器我里面有异步方法。(个人理解,可能会有瑕疵)。所以我们要真正实现异步,要将异步执行的调用(该例子中的while(true))放到Task中去执行,所以应该对代码做出如下修改:可以直接在主函数中调用
//没有返回值得task public async Task CircleUnReturn() { await Task.Run(() => { Console.WriteLine("当前线程ID:{0}", Thread.CurrentThread.ManagedThreadId); while (true) { } }); }
在不关注返回值得情况下,这种写法和单独使用Task没有区别,可以在调用函数中直接写下面的代码:
var taskUnReturn = Task.Run(() => { Console.WriteLine("当前线程ID:{0}", Thread.CurrentThread.ManagedThreadId); while (true) { } }); //和CircleUnReturn相同,只是代码位置换了一下
执行程序可以看到,两种方式都立即输出了线程ID,并且没有影响其他线程的执行:
使用方法:
当我们需要线程的返回值时:
异步函数TestAsync1包含了异步处理数据的方法(Task),使用另一个Async修饰的函数testAsync获取testAsync1的返回值。
如果我们不需要返回值可以直接调用testAsync1();
两种TestAsync1写法相同
public MainWindow() { InitializeComponent(); testAysnc2();//需要返回值 testAsync1(); //不需要返回值 } private async Task testAysnc2() { var t = testAsync1(); await t; Console.WriteLine(t.Result); } private async Task<string> testAsync1(string way1) { Console.WriteLine("Enter TestAsync1"); Task<string> task = new Task<string>(() => { for (int i=0; i<5; i++) { Thread.Sleep(1000); Console.WriteLine(Thread.CurrentThread.ThreadState); } return Thread.CurrentThread.ThreadState.ToString()+" Completed"; }); task.Start(); return await task; } private async Task<string> testAsync1() { Console.WriteLine("Enter TestAsync1"); return await Task.Run(() => { for (int i = 0; i < 5; i++) { Thread.Sleep(1000); Console.WriteLine(Thread.CurrentThread.ThreadState); } return Thread.CurrentThread.ThreadState.ToString() + " Completed"; }); }
欢迎加群一起深入学习WPF/.Net/C#:Hello WPF