• 异步:Task、Async、await、委托异步(Invoke、BeginInvoke、EndInvoke)


    参考:

    官方文档  c#使用 Async 和 Await 的异步编程  、 c#异步编程、 .NET 中的并行处理、并发和异步编程     前台和后台线程

    C#执行异步操作的几种方式比较和总结

    异步与多线程的区别(异步是目的,多线程是实现它的一种方式,异步的优先级有时候比主线程还高) - 子福当自强 - 博客园

    c#异步编程 

    JavaScript异步机制与异步原理

    异步编程的本质:绑定 - zzfx - 博客园

    异步编程的本质:怎么处理异步请求(事件)与响应的关系

    进阶篇:以IL为剑,直指async/await

    .NET 异步详解 --能说清楚异步与多线程的区别,涉及到操作系统原理(重点)

    异步和多线程有什么区别

    await,async 我要把它翻个底朝天,这回你总该明白了吧

    DotNetty完全教程(一)

    IO模型和基于事件驱动的IO多路复用模式

    ASP.NET Core使用Ping判断网络是否接通

    Nodes:Node.js异步机制和基本原理

    Nodes异步是基于事件机制,.net异步是基于任务的异步编程模型

     

    异步开发是什么

    异步开发,就是利用线程技术,当执行一个占用时间长的任务时,不会阻止用户其它工作,而且其完成时会通知用户。

    虽然是通过多线程来实现异步,但是因为一般异步时耗时的操作都不是针对CPU的,所以对CPU压力影响不大。

    常用的是 基于任务的异步模式 (TAP)

    异步本质是通过线程池提高线程的利用率。

    • 异步采用IO的DMA模式,不会消耗CPU资源。计算密集的工作,采用多线程。IO密集的工作,采用异步
    • 举例:网络爬虫爬数据,如果数据很庞大,这个时候就需要使用异步了。
    • DMA:Direct Memory Access是IO的操作模式,可以直接访问内存,不经过CPU,不消耗CPU资源。
    • 异步和多线程区别就是,充分利用DMA释放CPU压力。
    • 异步实现方式:.net中实现异步的方式有定时器和多线程,一般都是使用多线程。

    使用场景

    • 要执行耗时且不需要立刻返回结果的操作,如:I/O操作、网络操作

    争议:

    有种说法是:异步是不阻塞当前主线程执行,通过子线程去执行,还有总说法刚好相反,具体参考:异步与线程阻塞

    疑问:多线程是实现异步的一种方式,还可以通过定时器来实现异步,又有人说异步不是多线程,异步是把前台现成改为后台现成而已? 异步和多线程Thread

    同步、异步、并行区别

    同步:代码执行顺序默认是一行一行执行的,要等当前行的代码执行完后,才会执行下一行的代码。

    异步:不用等当前行代码执行完毕就会执行下一行的代码。异步编程是一项关键技术,可以直接处理多个核心上的阻塞 I/O 和并发操作

    并行许多个人计算机和工作站都有多个 CPU 内核,以便多个线程能够同时执行。 为了利用硬件,你可以对代码进行并行化,以将工作分摊在多个处理器上。

    并行和多线程、异步和多线程有啥关系?

    异步和多线程:多线程是创建多个线程,消耗的是CPU,异步呢?

    异步方法返回类型:void、Task、Task<TResult>

    异步编程模式

    示例

    使用Task、async 、await 方式实现3个打印

    用WindowsForm创建一个叫“异步”的按钮,按钮内有三行代码分别打印的3个label的时间,打印2时使用的是异步方法,暂停3秒

      

            //异步按钮点击事件
            private void button1_Click(object sender, EventArgs e)
            {
                //打印1
                label1.Text = "打印1:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId;
                //打印2,异步方法
                Test();
                //打印3
                label3.Text = "打印3:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId;
            }
            //异步方法:启动另外一个线程
            public async Task Test()
            {
                await Task.Run(() =>
                {
                    Thread.Sleep(3000); //暂停3秒
                    label2.Text = "打印2:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                      + Thread.CurrentThread.ManagedThreadId;
                });
            } 

    效果:打印1显示,打印3跟着显示,打印2最后才出来,且打印2的线程ID都是不一样的,如下

    使用几个打印2异步方法基本同时执行,等待全部异步方法执行完毕后提示信息

            //异步按钮点击事件
            private void button1_Click(object sender, EventArgs e)
            {
                //打印1
                Console.WriteLine("打印1:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
    
                //打印2,调用异步方法
                var listTask = new List<Task>();
                listTask.Add(Test());//往List<Task>集合中添加任务
                listTask.Add(Test());
                listTask.Add(Test());
                Task.WhenAll(listTask.ToArray()).ContinueWith(((b) =>
                {
                    Console.WriteLine("异步完毕:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
                }));
    
                //打印3
                Console.WriteLine("打印3:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
            }
            // 异步方法:启动另外一个线程
            public async Task Test()
            {
                await Task.Run(() =>
                {
                    Thread.Sleep(3000); //暂停3秒
                    Console.WriteLine("打印2:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                        + Thread.CurrentThread.ManagedThreadId);
                });
            }

    执行效果:几个异步的打印2方法基本同时执行,等打印2完毕后,在提示异步完成

     

    使用异步委托模式来打印2

           //异步按钮点击事件
            private void button1_Click(object sender, EventArgs e)
            {
                //打印1
                Console.WriteLine("打印1:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
    
                //打印2:使用异步委托方式
                Action<int> d1 = oldTest;
                d1.BeginInvoke(2000, ((t)=> { Console.WriteLine("单个异步执行完成"); }), null);         
    
                //打印3
               Console.WriteLine("打印3:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
            }
            public delegate void TaskWhileDelegate(int ms); //定义委托,异步时使用
            public void oldTest(int ms)
            {
                Thread.Sleep(ms); //暂停3秒
                Console.WriteLine("异步委托打印2:" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.fff") + ",线程ID:"
                    + Thread.CurrentThread.ManagedThreadId);
            }

    执行效果 

     

    耗时方法超时后直接返回,不再执行

    如果test()方法执行要5秒,现在设置为3秒,那3秒后直接停止执行跳过这个方法

    如果test()方法执行要2秒,现在设置为3秒,那2秒后执行完跳过

    Task[] task = new Task[] { Task.Run(() => test()) };
    Task.WaitAny(task, 3000);

    问题:

    1. 以前的一个老项目是用WebForm做的项目,是.net framework 3.5的,想使用异步,就把项目升级到.net framework 7.2,结果发现用异步委托方式和最新的Task方式都不行,如果直接创建一个新的WebForm项目又可以,所以暂时不知道是哪里的问题,暂时记下,以后再深入探究
    如有错误,欢迎您指出。
    本文版权归作者和博客园共有,欢迎转载,但必须在文章页面给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    插入排序
    关于“Scrum敏捷项目管理”
    结对编程体会
    PSP(3.13——3.15)以及周记录
    关于“类似软件的评价”作业(续)
    关于“代码规范”,“Review”和“Check list”(续)
    关于“类似软件的评价”作业
    关于“代码规范”,“Review”和“Check list”
    关于PSP(个人软件过程)
    软件工程管理——第一次作业
  • 原文地址:https://www.cnblogs.com/qingyunye/p/12743775.html
Copyright © 2020-2023  润新知