.net 4.5 Async和Await异步编程

        在最近的一个项目中,需要一个线程(Thread)不停地检测图片数据,并对数据进行处理,为了保证运行效率,需要在合适的时间对线程挂起和唤醒,所以使用Thread.Suspen和Thread.Resume,在vs中会提示这两个函数已过时,而且使用时Suspen由于不会释放所占用的锁,造成死锁(在IDE中运行时会出现死锁的情况,单独运行exe未出现,但是这样使用不安全),所以只能想其他办法。发现.net 4.5中的Async和Await可以很好的实现所需要的功能,而且使用起来也很方便。


        Async,Await 异步编程(MSDN,很详细)


          使用 async 修饰符可将方法、lambda 表达式匿名方法指定为异步。   如果对方法或表达式使用此修饰符,则其称为异步方法。也就是使用Async修饰的方法,lambda表达式和匿名方法都是异步方法,比如(测试程序基于WPF):
在对话框生成之前定义一个返回值为Task<int>,Async修饰的方法,并在方法中执行了一个五秒的延迟,我们发现对话框立即弹出,CirleAsync并没有阻塞主对话框, 注意此处await 后面是Task.Delay(1000);

  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

                  


猜你喜欢

转载自blog.csdn.net/u012853614/article/details/80244217
4.5