.Net 异步编程详解

2018-06-22 07:47:57来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

  最近看了下关于.Net多线程异步编程的一些文章,趁着这段时间有空,来总结一下吧!

  实现异步编程的方式有很多,本文主要选择4种方式概述下,谈谈自己的一些理解!

第一种方法:使用异步委托。

  我们知道,C#在处理delegate关键字的时候,动态生成了两个方法:BeginInvoke()和EndInvoke()。其中BeginInvoke()方法返回的对象实现了IAsyncResult接口,而EndInvoke()方法需要一个IAsyncResult类型作为参数。所以,由BeginInvoke()方法返回的对象IAsyncResult,它允许调用的线程在后面通过EndInvoke()方法来获取异步方法返回的结果。为更直观的理解,下面直接通过例子来说明吧!

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test1
{
    class Program
    {
        static void Main(string[] args)
        {

            Async();
        }



        /// <summary>
        /// 定义一个委托
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private delegate int DelegaIn(int x, int y);

        private static void Async()
        {


            //输出正在执行的线程ID
            Console.WriteLine("输出正在执行的线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

            //异步模式下调用
            DelegaIn delegaObj = new DelegaIn(Add);
            IAsyncResult async = delegaObj.BeginInvoke(10, 20,null,null);



            //主线程继续执行其他任务
            Console.WriteLine("主线程继续执行其他任务!!!");
           

            int answer = delegaObj.EndInvoke(async);
            Console.WriteLine("Add方法结束结果:" + answer);


        }



        private static int Add(int x, int y)
        {

            System.Threading.Thread.Sleep(1000 * 5);
            //输出次线程ID
            Console.WriteLine("输出次线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Add方法开始");



            return x + y;
        }

    }
}

 

然后来看结果:

  我们可以看到控制台先是输出当前线程的ID,然后下一步我们看到会在异步模式下调用Add方法,并且Add方法还使用Sleep挂起了5秒,但我们的程序并没有被阻塞等待,而是直接输出主线程继续执行其他任务,最后等待异步返回结果。而且可以看到Add方法里面其实是创建了由运行时维护的工作者线程,它的线程ID是3。这就是使用异步委托的方式来异步编程,当然,这只是一个简单的异步例子,关于IAsyncResult接口还提供其他的一些操作,这里就不做过多的概述了。

 

第二种方法:使用System.Threading 下的Thread类。

  使用线程类Thread。其实就是手动给当前程序创建一个次线程:

1、创建一个ThreadStart (或者ParameterizedThreadStart) 委托。并把定义的方法地址传给委托。值得注意的是,ThreadStart 委托指向的是无返回值,无参数的方法。而ParameterizedThreadStart委托指向的是有参数的方法。

2、创建一个Thread对象,并把上述委托传递进来

3、调用Thread.Start() 方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace test2
{
    class Program
    {
        static void Main(string[] args)
        {
            RunThread();
        }



        private static void RunThread()
        {

            //输出正在执行的线程ID
            Console.WriteLine("输出正在执行的线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

            ThreadStart threadStart = new ThreadStart(Print);
             

            Thread thread = new Thread(threadStart);
            thread.Start();




            //主线程继续执行其他任务
            Console.WriteLine("主线程继续执行其他任务!!!");


        }



        private static void Print()
        {

            System.Threading.Thread.Sleep(1000 * 5);
            //输出次线程ID
            Console.WriteLine("输出次线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Print方法结束");



            
        }
    }
}

看结果和上面使用异步委托差不多。只不过这是我们使用手动创建次线程的方法来实现异步的。

 

第三种方法:使用TPL并行编程库。

   .Net4.0开始,微软引入了种新的多线程应用程序开发方法,即TPL并行编程库。其中使用Task类不必再直接的与线程和线程池打交道。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace test3
{
    class Program
    {
        static void Main(string[] args)
        {

            //输出正在执行的线程ID
            Console.WriteLine("输出正在执行的线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);

            Task.Factory.StartNew(Print);



            //主线程继续执行其他任务
            Console.WriteLine("主线程继续执行其他任务!!!");
            Console.ReadLine();
        }



        private static void Print()
        {

            System.Threading.Thread.Sleep(1000);
            //输出次线程ID
            Console.WriteLine("输出次线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Print方法结束");




        }
    }
}

结果:

  Task类可以轻松在次线程中调用方法,可以作为异步委托的简单替代品!!!

 

第四种方法:async和await异步调用。

 

  最后,来介绍下.Net4.5下新增的两个关键字。async和await。

  async关键字用来指定某个方法、Lambda表达式自动以异步的方式调用。通过async修改的方法,CLR会创建新的执行线程来处理任务。在调用async方法时,await会自动挂起当前线程,直到任务完成,离开async修饰的调用线程,才继续往下执行。

  我们来看一个Windows Forms 程序。

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ParallerForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }







       


        private   void button1_Click(object sender, EventArgs e)
        {


            

            ProcessFiles();



            btnImage1.Text = "主线程执行完毕";
             
            

        }
        

       

        private   void   ProcessFiles()
        {


            Thread.Sleep(3000);
            btnImage.Text = "次线程执行完毕";










        }

    }
}

 

  当点击按钮的时候,需要等待3秒钟,文本框才能接收到键盘的输入,整个窗体这个时候就是个阻塞状态。现在来使用async关键字修饰方法,使其异步执行。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ParallerForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }







       


        private async  void button1_Click(object sender, EventArgs e)
        {


            

            await ProcessFiles();



            btnImage1.Text = "主线程执行完毕";
             
            

        }
        

       

        private  async Task   ProcessFiles()
        {


            await Task.Run(() =>
            {
                Thread.Sleep(3000);
                btnImage.Text = "次线程执行完毕";
            });










        }

    }
}

  你会发现,点击按钮后,窗体不会阻塞,可以立即在文本区输入值。因为async关键字允许它以非阻塞的形式进行工作。然后在遇到await关键字的时候,线程将挂起,指导await的任务完成。同时,控制权将返回给方法的调用者。

  好了!到此为止,上文总共介绍了4种异步编程的方式,文中如有什么不妥之处,还望大家不吝赐教!!!

 



标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:NancyFx 2.0的开源框架的使用-ModelBinding(实现绑定)

下一篇:.net 提取多层嵌套的JSON