异步多线程

Posted johntang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步多线程相关的知识,希望对你有一定的参考价值。

进程

计算机概念,程序在服务器运行时占据全部计算机资源总和,虚拟的。包含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*****StartThread.CurrentThread.ManagedThreadId.ToString("00") DateTime.Now.ToString()");
            for (int i = 0; i < 5; i++)
            
                string name = string.Format($"button1_Clicki");
                this.DoSomethingLong(name);
            

            Console.WriteLine($"button1_Click*****EndThread.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_1i");
                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

 

以上是关于异步多线程的主要内容,如果未能解决你的问题,请参考以下文章

多线程更新UI的常用方法

8异步和多线程

C# Winform 多线程异步委托进度条

多线程 Thread 线程同步 synchronized

异步任务片段背景数据

Java多线程概述及创建