异步多线程(一)

进程

计算机概念,程序在服务器运行时占据全部计算机资源总和,虚拟的。包含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

猜你喜欢

转载自www.cnblogs.com/JohnTang/p/10981424.html