• 异步多线程(一)委托异步多线程


    进程

    计算机概念,程序在服务器运行时占据全部计算机资源总和,虚拟的。包含CPU、内存、网络、硬盘

    MSDN:

    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。

    而一个进程又是由多个线程所组成的。

    线程

    计算机概念,进程在响应操作时最小单位,也包含CPU、内存、网络、硬盘

    MSDN:              

    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

    多线程

    计算机概念,一个进程有多个线程同时运行。

    MSDN:

        多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

    为什么可以多线程

          多个CPU的核可以并行工作,

            48线程,这里的线程指的是模拟核

    CPU分片

    1s的处理能力分成1000份,操作系统调度着去响应不同的任务

            从宏观角度来说,就是多个任务在并发执行

            从微观角度来说,一个物理cpu同一时刻只能为一个任务服务

    并行:多核之间叫并行

    并发CPU分片的并发

     多线程其实是资源换性能,1 资源不是无限的  2 资源调度损耗

    多线程的好处: 

    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以 运行其它的线程而不是等待,这样就大大提高了程序的效率。

    多线程的不利之处

    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 多线程需要协调和管理,所以需要CPU时间跟踪线程; 

    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;线程太多会导致控制太复杂,最终可能造成很多Bug

    同步与异步

    同步:

         发起调用,完成后才继续下一行;非常符合开发思维,有序执行;

    异步:

    发起调用,不等待完成,直接进入下一行,启动一个新线程来完成方法的计算

    同步方法有序进行,异步多线程无序
      启动无序:线程资源是向操作系统申请的,由操作系统的调度策略决定,所以启动顺序随机。同一个任务同一个线程,执行时间也不确定,CPU分片
    以上相加,结束也无序

    同步方法慢,异步多线程方法快

      同步:只有一个线程计算 异步:因为多个线程并发计算

    同步方法卡界面,异步多线程方法不卡界面

      同步方法:            主线程(UI线程)忙于计算,无暇他顾
      异步多线程方法: 异步多线程方法不卡界面:主线程闲置,计算任务交给子线程完成

    同步代码示例:

            /// <summary>
            /// 同步方法
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
    
                Console.WriteLine($"button1_Click*****Start{Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString()}");
                for (int i = 0; i < 5; i++)
                {
                    string name = string.Format($"button1_Click{i}");
                    this.DoSomethingLong(name);
                }
    
                Console.WriteLine($"button1_Click*****End{Thread.CurrentThread.ManagedThreadId} {DateTime.Now.ToString()}");
            }

    程序执行完成,我们可以清晰的看到,同步方法是有序的执行

    委托异步多线程代码示例:

            /// <summary>
            /// 异步多线程
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button2_Click_1(object sender, EventArgs e)
            {
                Console.WriteLine($"****************button2_Click Start " +
                    $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                    $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    
                Action<string> action = this.DoSomethingLong;
             
                for (int i = 0; i < 5; i++)
                {
                    string name = string.Format($"button2_Click_1{i}");
                    action.BeginInvoke("button2_Click", null, null);//委托异步多线程调用
    
                }
    
                Console.WriteLine($"****************button2_Click End " +
                    $"{Thread.CurrentThread.ManagedThreadId.ToString("00")} " +
                    $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    
            }

    程序运行之后,我们会发现运行的结果是无序的

    委托异步多线程 回调

    将后续动作通过回调参数传递进去,子线程完成计算后,去调用这个回调委托。

    代码示例:

            /// <summary>
            /// 异步多线程回调、等待
            /// Action
            /// Func
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button3_Click(object sender, EventArgs e)
            {
                #region  回调
                {
                    Action<string> action = this.DoSomethingLong;
                    IAsyncResult asyncResult = null;//是对异步调用操作的描述
                    AsyncCallback callback = mm =>
                    {//这里是一个委托
    
                        Console.WriteLine($"{object.ReferenceEquals(mm, asyncResult)}");
                        Console.WriteLine($"button3_Click计算成功了。{mm.AsyncState}。{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    
                    };
    
                    //回调
    
                    action.BeginInvoke("button3_Click", callback, "嘿嘿");//先执行action然后回调 callback委托
                }
                #endregion
    
    
            }

    委托异步多线程等待的三种方式:

    IsComplate等待

    通过IsComplate等待,主线程在等待,边等待边提示

                #region IsComplate等待
                {
                    Action<string> action = this.DoSomethingLong;
                    IAsyncResult asyncResult = null;//是对异步调用操作的描述
                    AsyncCallback callback = mm =>
                    {
                        Console.WriteLine($"{object.ReferenceEquals(mm, asyncResult)}");
                        Console.WriteLine($"button3_Click计算成功了。{mm.AsyncState}。{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    };
                    //回调
                    asyncResult= action.BeginInvoke("button3_Click", callback, "嘿嘿");//先执行action然后回调 callback委托
                    int i = 0;
                    while (!asyncResult.IsCompleted)
                    {
                        Thread.Sleep(200);
                        if (i < 2)
                        {
                            Console.WriteLine($"正在充电{++i * 10}%....");
    
                        } else{
                            Console.WriteLine($"充电完成完成99.999999%....");
                        }
                     
                    }
                    Console.WriteLine("充电已完成,尽情的使用手机吧!");
    
                }
    
                #endregion

    程序执行完成的结果

    注意:根据调用,首先执行DoSomethingLong 方法,因为DoSomethingLong方法里有密集操作,所以程序会边等待边执行while里的判断语句以及方法体

    此时DoSomethingLong里的密集操作已执行完毕,接着执行callback里的方法

    WaitOne等待

    WaitOne等待,即时等待  限时等待

     asyncResult.AsyncWaitHandle.WaitOne();//直接等待任务完成
    asyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成
    asyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,超时就不等了

    EndInvoke等待

    即时等待,而且可以获取委托的返回值 一个异步操作只能End一次

                #region EndInvoke 
                Func<int> func = ()=>
                {
                    Thread.Sleep(2000);
    return DateTime.Now.Hour; }; int Result = func.Invoke(); IAsyncResult asyncResult = func.BeginInvoke(ar=> { //在方法里拿到结果 // int IResult = func.EndInvoke(ar); //对于每个异步操作,只能调用一次EndInvoke }, null); //在方法外得到结果 int EndResult = func.EndInvoke(asyncResult); #endregion
  • 相关阅读:
    MYSQL导入,导出命令。
    MySQL修改,表结构大幅修改
    Ajax
    js和jQuery的日常
    freemarker 分页取值
    Timer定时任务
    汉字相似度比较
    读取Properties键值对
    Python+requests+unittest+excel实现接口自动化测试框架
    Android App 压力测试方法(Monkey)
  • 原文地址:https://www.cnblogs.com/JohnTang/p/10981424.html
Copyright © 2020-2023  润新知