精华内容
下载资源
问答
  • C# await

    2021-05-27 09:03:31
    } } 上面的代码不能输出t,如果想正确的输出t,用await class Program { static void Main(string[] args) { new Program().AsyncFunc(); Console.WriteLine("Return to Main process"); Console.ReadKey(); } ...
        class Program
        {
            static void Main(string[] args)
            {
                new Program().AsyncFunc();
                Console.WriteLine("Return to Main process");
                Console.ReadKey();
            }
    
            private async Task AsyncFunc()
            {
                var t = Task.Run(() => {
                    Thread.Sleep(5000);
                    return "Hello I am TimeConsumingMethod";
                });
                Console.WriteLine(t);
            }
        }

    上面的代码不能输出t,如果想正确的输出t,用await

        class Program
        {
            static void Main(string[] args)
            {
                new Program().AsyncFunc();
                Console.WriteLine("Return to Main process");
                Console.ReadKey();
            }
    
            private async Task AsyncFunc()
            {
                var t = Task.Run(() => {
                    Thread.Sleep(5000);
                    return "Hello I am TimeConsumingMethod";
                });
                Console.WriteLine(await t);
            }
        }

    注意,即使用了await,依然是异步方法,不阻塞。

    下面演示的是await如何调用带参数的task,注意AsyncFunc2依旧是异步方法。

    
            private async Task AsyncFunc2()
            {
                Console.WriteLine(await TimeConsumingMethod());
            }
    
            //这个函数就是一个耗时函数,可能是IO密集型操作,也可能是cpu密集型工作。
            private Task<string> TimeConsumingMethod()
            {
                var task = Task.Run(() => {
                    Console.WriteLine("Helo I am TimeConsumingMethod2. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(5000);
                    Console.WriteLine("Helo I am TimeConsumingMethod2 after Sleep(5000). My Thread ID is :" + Thread.CurrentThread.ManagedThreadId);
                    return "Hello I am TimeConsumingMethod2";
                });
    
                return task;
            }

     

     

    展开全文
  • 主要介绍了c# await,async执行流的相关知识,文章讲解的非常细致,代码帮助理解和学习,感兴趣的朋友可以了解下
  • C# await 高级用法

    2019-01-04 09:32:00
    C# await 高级用法 原文:C# await 高级用法 本文告诉大家 await 的高级用法,包括底层原理。 昨天看到太子写了一段代码,我开始觉得他修改了编译器,要不然下面的代码怎么可以编译...
    原文:C# await 高级用法

    本文告诉大家 await 的高级用法,包括底层原理。

    昨天看到太子写了一段代码,我开始觉得他修改了编译器,要不然下面的代码怎么可以编译通过

    await "林德熙逗比";
    

    需要知道,基本可以添加 await 都是可以等待的类型,如 Task 。如果一个类需要可以被等待,那么这个类必须满足以下条件

    • 类里有一个 GetAwaiter 函数

    • GetAwaiter 有返回值,返回值需要继承 INotifyCompletion 并且有 bool IsCompleted { get; },GetResult(),void OnCompleted(Action continuation) 定义

    参见:如何实现一个可以用 await 异步等待的 Awaiter - walterlv

    但是上面的代码使用的是一个字符串,什么时候可以修改继承字符串?

    先让我来说下 await 原理,因为知道了原理,上面的代码实现很简单。看完了本文,你就会知道如何让几乎所有类型包括 int 、string 、自定义的类都支持 await 。

    如果真的不想看原理,那么请直接调到文章的最后,看到最后很快就知道如何做。

    原理

    在 .net 4.5 之后,框架默认提供 async 和 await 的语法糖,这时千万不要认为进入 await 就会进入一个新的线程,实际上不一定会进入一个新的线程才会调用 await 。

    那么 await 的语法糖写的是什么?实际上就是以前的 Begin xx 和 End xx 的语法糖。

    古时候的写法:

    foo.Beginxx();
    
    foo.Endxx(传入委托);
    

    这样大家就无法在一个流程写完,需要分为两个东西,而在 Continus with 下,就需要传入委托。如果委托里又使用了异步,那么又需要传入委托

           task.ContinueWith(_ =>
                {
                    Task t1 = new Task(() => { });
                    t1.ContinueWith((t2) =>
                    {
                        //可以看到如果进入很多的委托
                    });
                });
    

    所以这时就使用了 await ,可以让大家按照顺序写。

    await task;
    Task t1 = new Task(() => { });
    await t1;
    //可以看到这时不需要进入委托
    

    实际上 await 是在编译时支持的,请看进阶篇:以IL为剑,直指async/await - 布鲁克石 - 博客园

    而且千万不要认为 await 一定会进入一个新的线程,实际上他只是把需要写在多处的代码,可以按照流写下载,和写同步代码一样。如果感兴趣 await 不一定会进入一个新的线程请看 There Is No Thread

    使用

    因为 await 需要找到一个 GetAwaiter 函数,这个函数即使是扩展方法也可以,所以其实上面的代码是这样写的

    
        public static class KvpbamjhKsvm
        {
            public static HeabdsdnbKevx GetAwaiter(this string str)
            {
                return new HeabdsdnbKevx();
            }
        }
    
        public class HeabdsdnbKevx : INotifyCompletion
        {
            public bool IsCompleted { get; }
    
            public void GetResult()
            {
            }
    
            /// <inheritdoc />
            public void OnCompleted(Action continuation)
            {
            }
        }
    

    HeabdsdnbKevx 就是一个可以等待的类型

    现在就可以写出下面的代码

            private static void Main(string[] args)
            {
                DdngSiwchjux();
            }
    
            private static async void DdngSiwchjux()
            {
                await "林德熙逗比";
            }
    

    当然,上面的这个代码可以运行,不过不会返回什么。下面让我加上一句代码。

            private static void Main(string[] args)
            {
                DdngSiwchjux();
            }
    
            private static async void DdngSiwchjux()
            {
                await "林德熙逗比";
                Console.WriteLine("csdn");
            }
    

    这时可以看到,Console.WriteLine("csdn");不会运行,因为这时如果在 OnCompleted 函数打断点就可以看到,执行await "林德熙逗比"之后就进入OnCompleted 函数。从上面的原理可以知道,这个函数传入的参数就是两个awaitawait和函数结束之间的代码。如果需要让Console.WriteLine("csdn");运行,那么只需要在OnCompleted运行参数

       public void OnCompleted(Action continuation)
            {
                continuation();
            }
    

    但是作为一个挖坑专业的大神,怎么可以就扩展 string ,下面我把 int 进行扩展

        public static class KvpbamjhKsvm
        {
            public static HeabdsdnbKevx GetAwaiter(this int dxpbnzSce)
            {
                return new HeabdsdnbKevx();
            }
        }
    

    随意写一个值,然后进行等待

    现在我准备在 object 加一个扩展方法,所有类型都可以等待,然后把这个扩展方法的 namespace 写为 System ,这样大家就不知道这个是我写的,过了一年我就告诉大家这是 C# 的特性,所有的类都可以等待。但是这个特性需要开光才可以使用,你们直接建的项目没有开光所以没法使用这个特性。

    等待和不等待的区别

    虽然很多时候从原理上看,等待和不等待只是调用时机的问题。但是依旧遇到一些小伙伴一直以为全部的异步方法都需要await,看到我写了没有直接await的代码觉得很诡异,所以我在这里做个实验给大家看。

    下面的代码是最常见的代码,在 async Task 的方法使用 await ,这样就会等待这个方法完成,代码就和同步代码一样。

     await GagarLerecel();
    private static async Task GagarLerecel()
    

    例如我这样写

                await GagarLerecel();
    
            private static async Task GagarLerecel()
            {
                Write("GagarLerecel 开始");
                await Task.Delay(100);
                Write("GagarLerecel 完成");
            }
    

    输出就是按照顺序输出

    GagarLerecel 开始
    GagarLerecel 完成
    

    如果我修改一下代码,创建一个新的函数 CoujafuDarso 里面的代码和上面函数相同

            private static async Task CoujafuDarso()
            {
                Write("CoujafuDarso开始");
                await Task.Delay(100);
                Write("CoujafuDarso结束");
            }
    

    但是不在调用 CoujafuDarso 使用 await ,而是使用一个变量

                var aa = CoujafuDarso();
                Write("其他代码");
                await aa;
    

    就是这样的代码,我的小伙伴说,这样写不清真,实际上这样写也是清真的代码。在调用 CoujafuDarso 会在代码到第一个 await 函数就返回,于是先执行了CoujafuDarso开始,然后函数返回,执行Write("其他代码"),在最后await aa才等待函数把所有代码执行完成。所以可以看到下面输出

    CoujafuDarso开始
    其他代码
    CoujafuDarso结束
    

    但是不加 await 的呢?也就是函数一直都没有等待,我再写一个函数BotujawWorpay

            private static async Task BotujawWorpay()
            {
                Write("BotujawWorpay开始");
                await Task.Delay(100);
                Write("BotujawWorpay结束");
            }
    

    调用的时候没有等待

                BotujawWorpay();
                Write("CesearJemmeme");
    

    这时会在输出CesearJemmeme之后,某个时间继续执行函数

    BotujawWorpay开始
    CesearJemmeme
    BotujawWorpay结束
    

    这样和使用 void 函数有什么区别?

    在执行的函数遇到第一个 await 就会返回,这样就可以继续执行函数下面的代码

    输出下面代码

    德熙逗比代码
    BarpooseewhowGelpousacall 代码1 线程1
    德熙逗比状态开始
    BarpooseewhowGelpousacall 代码2 线程5
    BarpooseewhowGelpousacall 代码3 线程4
    BarpooseewhowGelpousacall 完成 线程5
    

    多线程

    不是所有的 await 都会开多线程,如下面的代码

           static void Main(string[] args)
            {
                Write("开始");
                Write("线程" + Thread.CurrentThread.ManagedThreadId);
    
                CeaXisci();
                Task.Run(async () =>
                {
                    await Task.Delay(1000);
                    MouvaypuNasjo();
                });
                while (true)
                {
                    Console.Read();
                }
            }
    
            private static async Task BarpooseewhowGelpousacall()
            {
                Write("BarpooseewhowGelpousacall 代码1 线程" + Thread.CurrentThread.ManagedThreadId);
                await Task.Delay(10);
                Write("BarpooseewhowGelpousacall 代码2 线程" + Thread.CurrentThread.ManagedThreadId);
                await Task.Delay(10);
                Write("BarpooseewhowGelpousacall 完成 线程" + Thread.CurrentThread.ManagedThreadId);
            }
    

    也就是在没有Task.Delay分开的代码,只要使用了 await 那么就可以在同个线程运行,请看输出。在最后的BarpooseewhowGelpousacall 完成和这个函数后面的代码都在同一个线程运行,而上面的代码,可能是在同个线程,也可能在不同的线程

    开始
    线程1
    CeaXisci 开始 线程1
    BarpooseewhowGelpousacall 代码1 线程1
    BarpooseewhowGelpousacall 代码2 线程5
    BarpooseewhowGelpousacall 完成 线程4
    CeaXisci 开始 完成4
    

    相关博客

    使用 Task.Wait()?立刻死锁(deadlock) - walterlv

    如何实现一个可以用 await 异步等待的 Awaiter


    本文会经常更新,请阅读原文: https://lindexi.gitee.io/lindexi/post/C-await-%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

    知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://lindexi.gitee.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

    posted on 2019-01-04 09:32 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/10218070.html

    展开全文
  • 关于c# await使用总结

    千次阅读 2019-08-16 16:10:41
    在开发一个模拟人工自动网银转账的软件的时候,大量使用了async+await,在项目成功上线并且迭代了若干版本后,对于await相关的代码进行了重构,目前的结构更清晰,可扩展性更强。同时对于await的使用也从很初级,变...

     

    在开发一个模拟人工自动网银转账的软件的时候,大量使用了async+await,在项目成功上线并且迭代了若干版本后,对于await相关的代码进行了重构,目前的结构更清晰,可扩展性更强。同时对于await的使用也从很初级,变得有一些经验,现在把这些经验总结如下:

    1 await和async配对使用。最典型的应用如下:

    下面的代码是不用线程的情况,winform就会在5秒的无响应状态后才会在testbox中显示“test”,用户体验不好。

    ​
    private string testString()
    {
    
         Thread.Sleep(5000);
    
         return "test";
    
    }
    
    private async void btnGetAndTransfer_Click(object sender, EventArgs e)
    {
        tbTextBox.text=testString();
    }
    
    ​

     下面的代码使用传统的threading技术更新textbox的内容,非常复杂,代码难于维护

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            new Thread(SampleFunction).Start();
        }
    
        public void SetTextBox(string value)
        {
            if (InvokeRequired)
            {
                this.Invoke(new Action<string>(SetTextBox), new object[] {value});
                return;
            }
            textBox1.Text = value;
        }
    
        void SampleFunction()
        {
    
                Thread.Sleep(5000);
                SetTextBox("test");
                
        }
    }

    下面的代码使用await+async实现了第一段代码的功能,并且解决了winform冻结的问题。从代码的结构来说,也是清晰易读。 

    private async Task<string> testString()
    {
          return await Task<string>.Run(() =>
                {
                    Thread.Sleep(5000);
    
                    return "test";
                });
    }
    
    private async void btnGetAndTransfer_Click(object sender, EventArgs e)
    {
        tbTextBox.text=await testString();
    }

    从以上的代码示例来看await+async虽然是语法糖,但是有明显的的优势。

    2 虽然await+async有以上所说的优点,但是,如果大规模使用一定要慎重:

       a 方法体中使用await,方法也必须声明为async,另一个方法调用声明了async的方法,也需要用await,如果不用await,就会立即从被调用方法返回,继续执行后面的代码,而不会等待被调用async方法实际执行完毕再继续执行后面的代码。但是大多数情况下,调用async 方法都需要等待对方执行完再继续执行后面的代码,结果就因为某个方法里面用了await,导致调用它的整个call stack上的method都需要await+async,搞得很多代码被await传染。

      b 我在代码中用到了Action,就是为了可以把配置文件中的字符串对应执行相应的方法。但是,Action是个template class,不能同时兼容async和非async方法,结果导致用了await的方法只能另外处理。(Action应该也可以使用async方法,参考:https://stackoverflow.com/questions/20624667/how-do-you-implement-an-async-action-delegate-method

    3 从代码整体的架构设计来说,如果一个很深的call stack都用了await,那么就可以换个思路,不要让最里面的方法启动线程,而是把启动线程的代码放到最外面,这样一来绝大部分方法就都不再需要用async修饰了,方法就都可以用正常的方式开发了,也不会再把async传染到新的模块中。

    换句话说,async和await应该在贴近UI的地方使用,不要在基础功能的代码中使用。

    展开全文
  • c# await和async入门

    2019-12-08 22:44:34
    await async都是所谓的上下文关键字。上下文关键字,就是在特殊的语境下是关键字,脱离语境就是普通的标识符 二、怎么用(大匠诲人必以规矩的规矩) async 用来修饰方法,表明方法是异步的。方法的返回值必须是...

    一、是什么:

            await async都是所谓的上下文关键字。上下文关键字,就是在特殊的语境下是关键字,脱离语境就是普通的标识符

    二、怎么用(大匠诲人必以规矩的规矩)

    async 用来修饰方法,表明方法是异步的。方法的返回值必须是void、Task、Task<TResult>其中的一种。

    await表示等待某个任务执行完。await必须用来修饰Task或Task<TResult>类型的变量。并且await只能放在async函数中。

    async/await必须成对出现才有意义。await必须放在async修饰的函数中,async中出现await才有可能出现异步的效果。如果async中没有出现await的话,它就是一个普通的方法

    三、理解

    await的主语是await下面的代码,是await下面的代码等待await修饰的逻辑执行完,然后执行自身;

    async标志的就是异步的方法。async 内部必须有awati,也就是说必须有这个,才会有异步的效果;

    async 范围void,task,和task<T>。返回task是为了在某个取值的地方能够阻塞当前函数;

    许多返回Task的方法,其实是在内部开启了一个线程,并且返回Task时,线程已经启动了。

    四、写个代码去验证自己的理解

    反复的调整代码,去验证自己认为的那个结论是否正确,然后记住。记住便是获得了第一层次的知识。

     class Program
        {
            static void Main(string[] args)
            {
                MyClass cc = new MyClass();
                Console.ReadKey();
            }
        }
        public class MyClass
        {
            public MyClass()
            {
                var task=DisplayValue(); //这里不会阻塞
                task.ContinueWith(t => Console.WriteLine("内部完成."));
                Console.WriteLine("MyClass() End.");
               
            }
            public Task<double> GetValueAsync(double num1, double num2)
            {
                return Task.Run(() =>
                {
                    for (int i = 0; i < 1000000; i++)
                    {
                        num1 = num1 / num2;
                    }
                    return num1;
                });
            }
            public async Task DisplayValue()
            {
                double result = await GetValueAsync(1234.5, 1.01);//此处会开新线程处理GetValueAsync任务,然后方法马上返回
                                                                  //这之后的所有代码都会被封装成委托,在GetValueAsync任务完成时调用
               Console.WriteLine("Value is : " + result);
                
            }
        }
    

     

    参考文献:

    Task的异步模式

    C#异步编程之浅谈Task

    Task.Run 和 Task.Factory.StartNew 区别

    说说C#的async和await

     

    ***一个开启UI线程的小函数,面对它思考五分钟,你终有所得。

    一般返回task的方法,在task在返回之前,线程就已经开始了,实际代码类似于下面

    public static Task StartSTATask(Action action)
            {
                var tcs = new TaskCompletionSource<object>();
                var thread = new Thread(() =>
                {
                    try
                    {
                        action();
                        tcs.SetResult(null);
                    }
                    catch (Exception e)
                    {
                        tcs.SetException(e);
                    }
                });
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
                return tcs.Task;
            }

    展开全文
  • c# await的用法

    2020-02-01 16:58:12
    1 await和async配对使用。最典型的应用如下: 下面的代码是不用线程的情况,winform就会在5秒的无响应状态后才会在testbox中显示“test”,用户体验不好。 ​ private string testString() { Thread.Sleep...
  • C# await async Task

    2019-07-16 10:58:00
    //原文:https://www.cnblogs.com/yan7/p/8401681.html //原文:https://www.cnblogs.com/s5689412/p/10073507.html public void test2() ... //在出现await的地方,异步才开始发生 ...
  • C# await async lambda

    2020-05-13 10:45:45
    var ret = await task; this.ssxxx.Text = ret.ToString(); } //另外一个测试 private async void Button_Click(object sender, RoutedEventArgs e) { ssxxx.Text = "Start"; Task<int> task = mywaitFunc(1100); ...
  • c# await async 的初步理解

    千次阅读 2019-07-29 15:09:32
    学习完深入理解C#关于await 和 async的一些总结: 1. await async 的用法 2. await的一些限制 3.异步模式 4.可等待模式 5.从编译器的角度去理解 1. await async 的用法 async为修饰符用于在函数的返回值...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,705
精华内容 5,882
关键字:

c#await

c# 订阅