• (41)C#异步编程


    VS2010是经常阻塞UI线程的应用程序之一。例如用vs2010打开一个包含数百个项目的解决方案,可以要等待很长时间(感觉像卡死),自从vs2012情况得到了改善,项目在后台进行了异步加载。

    一、同步模式

    二、异步模式

    三、基于事件的异步模式

    四、基于任务的异步模式

    4.5以后更新基于任务的异步模式。

    1.最基本的任务

    普通方法

            public  string A()
            {
                return "abc";
            }

    (1)基于任务的模式带有 Async后缀的方法,并返回一个Task类型。

            public Task<string> AAsync()
            {
                return Task.Run(() => A());
            }

    其中Task<string>是一个返回字符串的任务。

    用Task.Run方法在线程池上执行一个方法,并返回一个任务对象。

    (2)使用关键字await来调用返回的任务 ,await关键字需要用带 Async修饰符的方法声明.

            public async void BAsync()
            {
                string str = await AAsync();
                Console.WriteLine("abc");
            } 

    Async修饰符只能用于返回Task<>或者void的方法。而且Async不能修饰Main。await只能返回Task的方法

    完整代码,执行一个异步任务

    例1

        class Program
        {
            static void Main(string[] args)
            {
                Program p = new Program();
                p.BAsync();
                Console.ReadKey();
            }
            public  string A()
            {
                return "abc";
            }
            public Task<string> AAsync()
            {
                return  Task.Run(() => A());
            }
            public async void BAsync()
            {
                string str = await AAsync();
                Console.WriteLine("abc");
            }   
        }

    任务完成后执行

        class Program
        {
            static void Main(string[] args)
            {
                Program p = new Program();
                p.C();
                Console.ReadKey();
            }
            public  string A()
            {
                return "abc";
            }
            public Task<string> AAsync()
            {
                return Task.Run(() => A());
            }
            public void C()
            {
                //用task对象接收返回对象
                Task<string> t1 = AAsync();
                //任务完成后调用的代码
                t1.ContinueWith(t =>
                {
                    Thread.Sleep(3000);
                    string s = t.Result;
                    Console.WriteLine(s);
                });
                Console.WriteLine("efg");
            }
        }

    (3)使用await async关键字,当await完成之后,不需要进行任何特别处理,就能访问UI线程

    ???

    (4)使用多个异步方法

    按顺序调用异步

    修改例1 的BAsync()方法

            public async void BAsync()
            {
                string str = await AAsync();
                string str2 = await AAsync() + "d";
                Console.WriteLine("{0},{1}",str,str2);
            }

    如果一个异步依赖另一个异步方法的结果,await非常有用,如果完全独立,每个异步方法都不使用await,整个方法将更快返回结果

    组合器

    一个组合器可以接受多个同一类型的参数,并返回同一类型的值。

            public async void BAsync()
            {
                Task<string> T1 =  AAsync();
                Task<string> T2 = AAsync();
                //等待,直到两个任务完成,返回task
                await Task.WhenAll(T1,T2);
                Console.WriteLine("{0},{1}", T1.Result, T2.Result);
                //也可用于返回数组
                string[] res= await Task.WhenAll(T1, T2);
                Console.WriteLine("{0},{1}", res[0], res[1]);
                //其中一个完成就返回task
                await Task.WhenAny(T1, T2);
            }

    (5)转换异步模式

    2.错误处理

    3.取消

     五、委托进行异步编程

    1.BeginInvoke()
    异步启动委托, 参数与要执行的方法的参数相同,另加两个可选参数
    第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。
    第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。
    BeginInvoke 将立即返回,而不会等待异步调用完成。
    BeginInvoke 返回可用于监视异步调用的进度的 IAsyncResult。
    IAsyncResult 对象 =委托对象.BeginInvoke(定义委托时有几个参数,AsyncCallback ,类的对象);

    2.EndInvoke()
    EndInvoke 方法用于检索异步调用的结果,它可以在调用 BeginInvoke之后的任意时间调用。
    如果异步调用尚未完成,那么 EndInvoke 将阻止调用线程,直到完成异步调用。
    这种方式非常适合执行文件或网络操作。

    (1)使用 EndInvoke 等待异步调用

    在控制台下运行

    新建了一个测试类,一个用来同步,一个用来异步。

        class Program
        {
            public delegate string delegateClass(int time);
            static void Main(string[] args)
            {
                TextClass textClass = new TextClass();
                //把要执行的异步方法存入委托
                delegateClass testMethod = new delegateClass(textClass.asynMethod);
                //启动异步委托,参数一有没有取决于定义委托时的参数有没有
                IAsyncResult result = testMethod.BeginInvoke(3000, null, null);
                //当异步委托结束后,把该委托返回的值回传给str
                string str1 = testMethod.EndInvoke(result);
                Console.WriteLine(str1);
                Console.WriteLine("...............");
                //运行同步方法
                string str2 = textClass.synMethod(0);
                Console.WriteLine(str2);
                Console.ReadKey();
            }
        }
        //测试类
        class TextClass
        {
            //用来同步
            public string synMethod(int time)
            {
                Console.WriteLine("启动同步方法");
                Thread.Sleep(time);
                Console.WriteLine("结束同步方法");
                return "同步返回";
            }
            //用来异步
            public string asynMethod(int time)
            {
                Console.WriteLine("启动异步方法");
                Thread.Sleep(time);
                Console.WriteLine("结束异步方法");
                return "异步返回";
            }
        }

    运行结果:

     发现结果异步操作执行后,才执行的同步操作。

    然后注释掉“等待异步调用的方法

    //string str1 = testMethod.EndInvoke(result);
    //Console.WriteLine(str1);

    在运行:

    EndInvoke()方法会把所在的线程卡住(阻塞

    所以如果在winfrom下运行EndInvoke(),在异步未执行完的条件下会把界面卡死。EndInvoke方法不能和用户界面在同一个线程下

    (2)对异步调用的完成情况进行轮询

     

            public delegate string delegateClass(int time);
            static void Main(string[] args)
            {
                TextClass textClass = new TextClass();
                //把要执行的异步方法存入委托
                delegateClass testMethod = new delegateClass(textClass.asynMethod);
                //启动异步委托
                IAsyncResult result = testMethod.BeginInvoke(3000, null, null);
                //如果异步为执行完成,会不断循环执行此方法。
                while (result.IsCompleted == false)
                {
                    //Thread.Sleep(350);
                    Console.Write("a");
                }
                //当异步委托结束后,把该委托返回的值回传给str
                string str1 = testMethod.EndInvoke(result);
                Console.WriteLine(str1);
                Console.ReadKey();
            }
        }
        //测试类
        class TextClass
        {
            //用来异步
            public string asynMethod(int time)
            {
                Console.WriteLine("启动异步方法");
                Thread.Sleep(time);
                Console.WriteLine("b");
                Console.WriteLine("结束异步方法");
                return "异步返回";
            }
        }

    结果

    (3)异步调用完成时执行回调方法

     winfrom

        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                //是否捕获对错误线程的调用
                Control.CheckForIllegalCrossThreadCalls = false;
            }
            //
            private delegate string delegatehWeb();
            delegatehWeb delWeb=new delegatehWeb(webReuest);
            private void button1_Click(object sender, EventArgs e)
            {
                //执行异步,异步结束后,执行Callback方法
                IAsyncResult result = delWeb.BeginInvoke(Callback, null);
                textBox1.Text = "HTML代码";
            }   
            
            //回调方法
            public void Callback(IAsyncResult result)
            {
                string str = delWeb.EndInvoke(result);
                textBox1.Text = str;
                //MessageBox.Show(str);
            }
            
            //获取网站HTML
            public static string webReuest()
            {
                HttpWebRequest httpWebRequest = WebRequest.CreateHttp("http://www.baidu.com/");
                WebResponse httpWebResponse = httpWebRequest.GetResponse();
                //返回数据流
                Stream stream = httpWebResponse.GetResponseStream();
                Encoding encode = Encoding.GetEncoding("utf-8");
                StreamReader readStream = new StreamReader(stream, encode);
                //把流转成字符串
                string htmlStr = readStream.ReadToEnd();
                Thread.Sleep(3000);
                return htmlStr;
            }
        }

     task 执行异步任务, t.Wait()阻塞所在线程

            private void button1_Click(object sender, EventArgs e)
            {
                Task t = Task.Run(() => {
                    Thread.Sleep(3000);
              //所在线程id MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId)); }); MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId)); //等待task完成后向后执行 t.Wait(); MessageBox.Show(Convert.ToString(Thread.CurrentThread.ManagedThreadId)); }
  • 相关阅读:
    [WinAPI] API 9 [文件的删除、复制和移动功能]
    2014-3-7 星期五 [困]
    2014-3-6 星期四 [第一天执行分析]
    [WinAPI] API 8 [获取磁盘空间信息]
    [WinAPI] API 7 [判断光驱内是否有光盘]
    [WinAPI] API 6 [操作驱动器挂载点]
    Eclipse 生成WebService客户端代码
    Windows7下安装与破解IntelliJ IDEA2017(转载)
    Tomcat的安装
    IntelliJ IDEA的几种常见的快捷键
  • 原文地址:https://www.cnblogs.com/buchizaodian/p/8478469.html
Copyright © 2020-2023  润新知