zoukankan      html  css  js  c++  java
  • C#巧妙使用关键字async/await

    原文链接(程序杰杰):https://www.cnblogs.com/ningxinjie/p/12008561.html

    经过一番的探索,终于搞清楚关键字async/await 在.net4.5之后可用的巧妙之处,在这里记录一下也与大家分享一下个人的心得体会

    async:异步执行

    await:异步执行中的等待其执行完(最大的优点是它是后台等待,因此不阻塞GUI,界面交互非常的好)

    使用async方法要定义async Task或者async Task<T> 最好不要定义async void方法来调用,async void是处理程序等,总结结论就是要使用async Task或者async Task<T> 

    使用asyn方法,可以用同步的格式,执行异步的代码,如下:

     1         int a = 0;
     2         private void button1_Click(object sender, EventArgs e)
     3         {
     4             Task.Run(()=> {
     5                 Stopwatch sw = new Stopwatch();
     6                 sw.Start();
     7                 Thread.Sleep(2000);
     8                 sw.Stop();
     9                 SetText(textBox1,this, sw.ElapsedMilliseconds.ToString());
    10             });
    11             var eee=Ce_async();//前面接收值,这样方法立即返回,主线程继续执行
    12             //eee.IsCompleted
    13             textBox3.Text = "主线程继续向下执行";
    14 
    15 
    16         }
    17         private async Task Ce_async()
    18         {
    19             await Task.Run(async ()=> {
    20                 while (true)
    21                 {
    22                     await Task.Delay(100);//Thread.Sleep(2000);23                     a += 1;
    24                     SetText(textBox2, this, a.ToString());
    25                 }
    26             });
    27         }
    28 
    29 
    30 
    31         private delegate void SetTextdelegate(Control cr,Form f,string str);
    32         private void SetText(Control cr, Form f, string str)
    33         {
    34             if (f.InvokeRequired) { f.Invoke(new SetTextdelegate(SetText), cr, f, str); }
    35             else { cr.Text = str; }
    36         }

    正如上图第11行注释,使用接收值来接收async方法,该方法会立即返回值,主程序继续向下执行,该方法后台继续跑。

    那么肯定有小伙伴与我当初有同样的疑惑,这样我执行用线程在这里执行不也可以吗?为什么要用async关键字呢,他到底有什么好处?

    比如有一种情况:我的主线程如何有需要休眠等待的情况,那么直接使用Thread.Sleep(),会使界面卡死,如果此时我将方法修改为async,那么只需要await Task.Delay() 这样也会等待时间完成后再向下执行,但是它不会使主界面处于假死状态,如下:

     1    private async void button1_Click(object sender, EventArgs e)
     2         {
     3             await Task.Delay(1000);
     4             var aaa=Task.Run(() =>
     5             {
     6                 Stopwatch sw = new Stopwatch();
     7                 sw.Start();
     8                 Thread.Sleep(2000);
     9                 sw.Stop();
    10                 SetText(textBox1, this, sw.ElapsedMilliseconds.ToString());
    11             });
    12             var eee=Ce_async();//前面接收值,这样方法立即返回,主线程继续执行
    13             //eee.IsCompleted
    14             textBox3.Text = "主线程继续向下执行";
    15         }

    再次重复一点,在async方法中使用接收值来接收Task,会使得Task不必加上await关键字而被迫使得主线程需要等待它执行完才能向下执行,接收值的目的就是立即得到返回值

    使用接收值来接收Task会直接返回,代码继续向下执行,这一点很重要!!!

    上图的第3行,如下:

    await Task.Delay(1000);

    其中await只能用在异步方法中,await会使得该线程等待await处的线程执行完,方可执行下方代码,正如该处代码所示,使用await Task.Delay(100); 代替 Thread.Sleep(100)

    对于有返回值的这样来写:

    Form1中按钮代码如下:

      private async void button1_Click(object sender, EventArgs e)
            {
               string a= await new Class1().Ceshifunc();
               MessageBox.Show(a);
            }

    执行的Class1类方法为:

      public class Class1
        {
            private static readonly object obj = new object();
            public Task<String> Ceshifunc()
            {
                lock (obj)
                {
                    var task = Task.Run(()=>
                    {
                        Thread.Sleep(5000);
                        return "ok";
                    });
                    return task;
                }
            }
        }

     这样操作无卡顿,但是仍然无法实现lock内无法await,因为lock内的代码是task,他不会等待task执行完再返回,而是返回出去再执行,因此相当于没lock一样

    我将所有代码放入Form1下

        private static readonly object obj = new object();
            public Task<String> Ceshifunc(string str, Form form, TextBox tb)
            {
                var task = Task.Run(() =>
                {
                    lock (obj)
                    {
                        string aa = label1.Text;
                        SetText(label1, this, aa + "1");
                        Thread.Sleep(2000);
                        SetText(tb, form, str);
                        return str;
                    }
                });
                return task;
            }
    
            public Action<Control, Form, string> setText;
            public void SetText(Control tb, Form form, string str)
            {
                setText += SetText;
                if (form.InvokeRequired) { form.Invoke(setText, tb, form, str); }
                else { tb.Text = str; }
            }

    按钮事件为:

      private async void button1_Click(object sender, EventArgs e)
            {
                string a = await Ceshifunc("b1", this, textBox1);
            }

     这样就可以实现了变相解决lock内的await使用

    个人推荐另一个博客原文链接地址:https://www.cnblogs.com/mqxs/p/6550274.html

     以上就是个人的心得体会,(转载请注明)(程序杰杰)原文链接:https://www.cnblogs.com/ningxinjie/p/12008561.html



  • 相关阅读:
    js获取多选框选择的值并拼接成字符串
    把不可枚举数组转换成可枚举数组
    js对接图片上传接口
    填数字游戏解题机
    带你深入了解nginx基本登录认证(包含配置步骤)
    高三whk回忆录
    SpringBoot异步任务
    Shell 脚本
    【Ubuntu】知识点及经验
    【Ubuntu】 安装相关
  • 原文地址:https://www.cnblogs.com/ningxinjie/p/12008561.html
Copyright © 2011-2022 走看看