异步多线程知识点总结-------仅供参考(基础用法)

基本概念:

 

什么是进程,线程和多线程:

进程:一个程序运行时,占用的全部计算资源的总和;进程之间是相互独立的。

线程:

  1. 是windows任务调度的最小单位。
  2. 线程是程序中的一个执行流
  3. 所有的代码都必须执行在线程,有线程才能有代码执行

多线程:多个执行流同时运行

什么是同步异步:

他们只是对方法执行的描述

同步:完成一行计算后,再进入下一行。

异步:不会等待方法的完成,直接进入下一步操作。

异步多线程:

优点:1. 不卡界面,提升用户体验

           2.同步方法只有一个线程干活,速度慢;异步方法有多个线程一起干活速度快

           3.异步多线程,子线程启动无序,结束也无序。

训练准备:

一:首先创建一个控制台应用程序,添加Window窗体,定义几个按钮,开始进行Demo:

 二:控制台Program.cs写法

[STAThread]
static void Main(string[] args)
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

三:再Form1.cs定义一个方法方便后续使用

private void DoSomeThing(string name)
{
    Console.WriteLine($"*************DoSomeThing 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{name}{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
    long lResult = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        lResult += i;
    }
    Console.WriteLine($"*************DoSomeThing 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{name}{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}

 Thread:

 出现在1.0   1.1版本,基本摒弃不怎么使用,不需要解释,常用方法:

private void Threads_Click(object sender, EventArgs e)
{
    Console.WriteLine($"=====================Thread 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
    ThreadStart threadStart = () => this.DoSomeThing("Threads_Click");
    Thread thread = new Thread(threadStart);
    thread.Start();//开始线程
    //thread.Suspend();//线程挂起     已弃用
    //thread.Resume();//线程唤醒      已弃用
    //try
    //{
    //    thread.Abort();//销毁线程,方式为抛异常        不建议使用   不一定即时/有些动作发出可能停不下来
    //}
    //catch (Exception)
    //{
    //    Thread.ResetAbort();//取消异常
    //    throw;
    //}

    //线程等待
    //thread.Join(500);//最多等待500毫秒
    //Console.WriteLine("最多等待500毫秒");
    //thread.Join();//当前线程等待Thread完成
    //while (thread.ThreadState!=ThreadState.Stopped)
    //{
    //    Thread.Sleep(100);//当前线程休息100毫秒
    //}
    //thread.IsBackground = true;//指定后台线程:随着进程退出,默认为False,为前台线程,前台线程启动之后一定要完成任务
    //thread.Priority = ThreadPriority.Highest;//线程优先级   CPU会优先执行 Highest 不代表说Highest就最先完成    

    Console.WriteLine($"=====================Thread 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
}

 ThreadPool----线程池:

出现在2.0版本,优点:避免无线使用线程,加以限制。而且能够重用线程,避免重复创建和销毁

private void btnThreadPool_Click(object sender, EventArgs e)
{
    Console.WriteLine($"=====================ThreadPool 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
    //ThreadPool.QueueUserWorkItem(t => this.DoSomeThing("btnThreadPool_Click"));//--------------启动多线程

    //获取线程池请求最大的数目。 所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。
    {
        ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
        Console.WriteLine($"workerThreads=【{workerThreads}】----completionPortThreads=【{completionPortThreads}】");
    }
    //获取线程池请求最大的数目的最小数量。
    {
        ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
        Console.WriteLine($"workerThreads=【{workerThreads}】----completionPortThreads=【{completionPortThreads}】");
    }
    //设置线程池最大的线程数
    ThreadPool.SetMaxThreads(16, 16);
    //设置线程池最小的线程数
    ThreadPool.SetMinThreads(8, 8);
    Console.WriteLine("-----------------------------------设置后-----------------------------------------");
    //获取线程池请求最大的数目。 所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。
    {
        ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
        Console.WriteLine($"workerThreads=【{workerThreads}】----completionPortThreads=【{completionPortThreads}】");
    }
    //获取线程池请求最大的数目的最小数量。
    {
        ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
        Console.WriteLine($"workerThreads=【{workerThreads}】----completionPortThreads=【{completionPortThreads}】");
    }

    //-----------------------------------------线程等待---------------------------------------
    //ManualResetEvent为一个类,包含了一个布尔属性
    //false时,WaitOne等待,当执行Set时,ManualResetEvent变为true,不进行等待直接过去
    ManualResetEvent manualResetEvent = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(t =>
    {
        this.DoSomeThing("btnThreadPool_Click");
        manualResetEvent.Set();//ManualResetEvent变为true
        //manualResetEvent.Reset();//相反,设置为false

    });

    //一般来说,不要阻塞线程池的线程
    manualResetEvent.WaitOne();
    Console.WriteLine("等待QueueUserWorkItem完成后才执行");
    Console.WriteLine($"=====================ThreadPool 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
}

Task----最常用的

3.0版本出现,基于ThreadPool(线程池)

/// <summary>
/// 编码做项目
/// </summary>
/// <param name="name"></param>
/// <param name="project"></param>
private void Coding(string name, string project)
{
    Console.WriteLine($"****************Coding {name} Start {project} 【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
    long lResult = 0;
    for (int i = 0; i < 1000000000; i++)
    {
        lResult += i;
    }
    //Thread.Sleep(2000);

    Console.WriteLine($"****************Coding {name}   End {project} 【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
}

 private void btnTask_Click(object sender, EventArgs e)
 {
     Console.WriteLine($"=====================Task 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
     //启动多线程的三种方式
     //Task.Run(() => this.DoSomeThing("btnTask_Click1"));
     //new Task(() => this.DoSomeThing("btnTask_Click2")).Start();
     //TaskFactory taskFactory = Task.Factory;//4.0的时候出现
     //taskFactory.StartNew(() => this.DoSomeThing("btnTask_Click3"));//同样可以启动多线程

     //小场景
     //List<Task> taskList = new List<Task>();

     //Console.WriteLine($"----------项目经理启动项目--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //Console.WriteLine($"----------前置准备工作--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //Console.WriteLine($"----------开始编程--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //taskList.Add(Task.Run(() => this.Coding("张三", "前端")));
     //taskList.Add(Task.Run(() => this.Coding("李四", "后台")));
     //taskList.Add(Task.Run(() => this.Coding("王五", "服务")));
     //taskList.Add(Task.Run(() => this.Coding("赵六", "测试")));
     //taskList.Add(Task.Run(() => this.Coding("田七", "运维")));

     //Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等某个任务完成后,才进入下一行,会卡界面
     //Task.WaitAny(taskList.ToArray(),1000);//限时等待,会卡界面
     //Console.WriteLine($"--------------------完成一部分,简单庆祝----------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

     //Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等全部任务完成后,才进入下一行,会卡界面
     //Task.WaitAll(taskList.ToArray(), 1000);//限时等待,会卡界面
     //Console.WriteLine("等待了一秒");

     //子线程干的任务,不卡界面
     //{
     //    Task.WhenAny(taskList.ToArray()).ContinueWith(t =>
     //    {
     //        Console.WriteLine($"------------------第一个完成--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //    Task.WhenAll(taskList.ToArray()).ContinueWith(t =>
     //    {
     //        Console.WriteLine($"------------------部署环境,联调测试--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //}
     //和上面一样的效果
     //{
     //    TaskFactory taskFactory = Task.Factory;
     //    taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
     //    {
     //        Console.WriteLine($"------------------第一个完成--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //    taskFactory.ContinueWhenAll(taskList.ToArray(), t =>
     //    {
     //        Console.WriteLine($"------------------部署环境,联调测试--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //}

     //{
     //    List<int> list = new List<int>();
     //    for (int i = 0; i < 10000; i++)
     //    {
     //        list.Add(i);
     //    }
     //    //完成10000个任务,但只要11个线程
     //    Action<int> action = i =>
     //    {
     //        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00"));
     //        Thread.Sleep(new Random(i).Next(100, 300));
     //    };
     //    List<Task> taskList = new List<Task>();
     //    foreach (var i in list)
     //    {
     //        int k = i;
     //        taskList.Add(Task.Run(() => action.Invoke(k)));
     //        if (taskList.Count>10)
     //        {
     //            Task.WaitAny(taskList.ToArray());
     //            taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
     //        }
     //    }
     //    Task.WhenAll(taskList.ToArray());
     //}


     //{
     //    TaskFactory taskFactory = new TaskFactory();
     //    List<Task> tasksList = new List<Task>();
     //    tasksList.Add(taskFactory.StartNew(t => this.Coding("张三", "开发"), "张三"));
     //    tasksList.Add(taskFactory.StartNew(t => this.Coding("李四", "运维"), "李四"));
     //    tasksList.Add(taskFactory.StartNew(t => this.Coding("王五", "测试"), "王五"));
     //    taskFactory.ContinueWhenAny(tasksList.ToArray(), t =>
     //    {
     //        Console.WriteLine(t.AsyncState);
     //        Console.WriteLine($"------------------第一个完成--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //    taskFactory.ContinueWhenAll(tasksList.ToArray(), t =>
     //    {
     //        Console.WriteLine(t[t.Count()-1].AsyncState);
     //        Console.WriteLine($"------------------部署环境,联调测试--------------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });

     //}

     //没有什么是包一层解决不了的,实现WaitAny和WaitAll不卡界面
     //{
     //    List<Task> taskList = new List<Task>();
     //    Console.WriteLine($"----------项目经理启动项目--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    Console.WriteLine($"----------前置准备工作--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    Console.WriteLine($"----------开始编程--------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    Task.Run(() =>
     //    {
     //        taskList.Add(Task.Run(() => this.Coding("张三", "前端")));
     //        taskList.Add(Task.Run(() => this.Coding("李四", "后台")));
     //        taskList.Add(Task.Run(() => this.Coding("王五", "服务")));
     //        taskList.Add(Task.Run(() => this.Coding("赵六", "测试")));
     //        taskList.Add(Task.Run(() => this.Coding("田七", "运维")));

     //        Task.WaitAny(taskList.ToArray());//会阻塞当前线程,等某个任务完成后,才进入下一行,会卡界面
     //        Task.WaitAny(taskList.ToArray(), 1000);//限时等待,会卡界面
     //        Console.WriteLine($"--------------------完成一部分,简单庆祝----------------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

     //        Task.WaitAll(taskList.ToArray());//会阻塞当前线程,等全部任务完成后,才进入下一行,会卡界面
     //        Task.WaitAll(taskList.ToArray(), 1000);//限时等待,会卡界面
     //        Console.WriteLine("等待了一秒");
     //        //全部任务都完成才进行的操作
     //        Console.WriteLine($"----------甲方验收,上线使用---------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");
     //    });
     //}

     Task.Delay(1000);//延迟   不会卡
     Thread.Sleep(1000);//等待
     //全部任务都完成才进行的操作
     //Console.WriteLine($"----------甲方验收,上线使用---------【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】");

     Console.WriteLine($"=====================Task 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
 }

Parallel

并行编程,在Task的基础上做了封装
卡界面,主线程参与运算,节约了一个线程
 

private void btnParallel_Click(object sender, EventArgs e)
{
    Console.WriteLine($"=====================Parallel 开始【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
    //{
    //    Parallel.Invoke(
    //        () => Coding("张三", "前端")
    //        , () => Coding("李四", "后端")
    //        , () => Coding("王五", "运维")
    //        , () => Coding("赵六", "测试")
    //    );
    //}
    //{
    //    Parallel.For(0, 5, i => this.Coding("张三", "开发"));
    //}
    //{
    //    Parallel.ForEach(new string[] {"1","2","3" }, i => this.Coding("张三", "开发"));
    //}
    {
        //最多三个线程计算,控制并发数量
        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 3;
        Parallel.For(0, 5, parallelOptions, i => this.Coding("张三", "开发"));
    }
    Console.WriteLine($"=====================Parallel 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
}

多线程异常处理,线程取消,临时变量,锁

private static readonly object btnThreadCore_Click_Lock = new object();
private int TotalCount = 0;//
private List<int> IntList = new List<int>();
private void btnThreadCode_Click(object sender, EventArgs e)
{
    Console.WriteLine($"=====================ThreadCode 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
    try
    {
        TaskFactory taskFactory = new TaskFactory();
        List<Task> taskList = new List<Task>();
        #region 异常处理
        //线程里面的异常是被吞掉了,因为已经脱离try catch的范围了  WaitAll 抓到多线程里面全部的异常
        //线程里面的action不允许出现异常,自己处理好
        //for (int i = 0; i < 20; i++)
        //{
        //    string name = string.Format($"btnThreadCore_Click_{i}");
        //    Action<object> act = t =>
        //    {
        //        try
        //        {
        //            Thread.Sleep(2000);
        //            if (t.ToString().Equals("btnThreadCore_Click_11"))
        //            {
        //                throw new Exception(string.Format($"{t} 执行失败"));
        //            }
        //            if (t.ToString().Equals("btnThreadCore_Click_12"))
        //            {
        //                throw new Exception(string.Format($"{t} 执行失败"));
        //            }
        //            Console.WriteLine("{0} 执行成功", t);
        //        }
        //        catch (Exception ex)
        //        {
        //            Console.WriteLine($"Exception:{ex.Message}");
        //        }
        //    };
        //    taskList.Add(taskFactory.StartNew(act, name));
        //}
        //Task.WaitAll(taskList.ToArray());
        #endregion

        #region 线程取消
        //多个线程并发,某个失败后,希望通知别的线程,都停下来
        //task是外部无法中止,Thread.Abort不靠谱,因为线程是OS的资源,无法掌控啥时候取消
        //线程自己停止自己--公共的访问变量--修改它---线程不断的检测它(延迟少不了)
        //CancellationTokenSource去标志任务是否取消  Cancel取消   IsCancellationRequested  是否已经取消了
        //Token 启动Task的时候传入,那么如果Cancel了,这个任务会放弃启动,抛出一个异常
        CancellationTokenSource cts = new CancellationTokenSource();
        //for (int i = 0; i < 40; i++)
        //{
        //    string name = string.Format("btnThreadCore_Click{0}", i);
        //    Action<object> act = t =>
        //    {
        //        try
        //        {
        //            //if (cts.IsCancellationRequested)
        //            //{
        //            //    Console.WriteLine("{0} 取消一个任务的执行", t);
        //            //}
        //            Thread.Sleep(2000);
        //            if (t.ToString().Equals("btnThreadCore_Click11"))
        //            {
        //                throw new Exception(string.Format("{0} 执行失败", t));
        //            }
        //            if (t.ToString().Equals("btnThreadCore_Click12"))
        //            {
        //                throw new Exception(string.Format("{0} 执行失败", t));
        //            }
        //            if (cts.IsCancellationRequested)//检查信号量
        //            {
        //                Console.WriteLine("{0} 放弃执行", t);
        //                return;
        //            }
        //            else
        //            {
        //                Console.WriteLine("{0} 执行成功", t);
        //            }
        //        }
        //        catch (Exception ex)
        //        {
        //            cts.Cancel();
        //            Console.WriteLine(ex.Message);
        //        }
        //    };
        //    taskList.Add(taskFactory.StartNew(act, name, cts.Token));
        //}
        //Task.WaitAll(taskList.ToArray());
        #endregion

        #region 多线程临时变量
        //for (int i = 0; i < 5; i++)
        //{
        //    Task.Run(() =>
        //      {
        //          Thread.Sleep(100);
        //          Console.WriteLine(i);
        //      });
        //}

        //for (int i = 0; i < 5; i++)
        //{
        //    int k = i;
        //    Task.Run(() =>
        //    {
        //        Thread.Sleep(100);
        //        Console.WriteLine(k);
        //    });
        //}

        //i最后是5      全程就只有一个i  等着打印的时候,i==5
        //k             全程有5个k   分别是0 1 2 3 4 
        //k在外面声明   全程就只有一个k    等着打印的时候,k==4
        //int k = 0;
        //for (int i = 0; i < 5; i++)
        //{
        //    k = i;
        //    new Action(() =>
        //    {
        //        Thread.Sleep(100);
        //        Console.WriteLine($"k={k} i={i}");
        //    }).BeginInvoke(null, null);
        //}
        #endregion

        #region 线程安全 lock
        //共有变量:都能访问局部变量/全局变量/数据库的一个值/硬盘文件
        //线程内部不共享的是安全

        //lock 解决,因为只有一个线程可以进去,没有并发,所以解决了问题    但是牺牲了性能,所以要尽量缩小lock的范围
        //不要冲突--数据拆分,避免冲突

        //安全队列 ConcurrentQueue  一个线程去完成操作
        int TotalCountIn = 0;//有问题
        for (int i = 0; i < 10000; i++)//i有问题
        {
            int newI = i;//没问题 全新的newI
            taskList.Add(taskFactory.StartNew(() =>
            {
                //int m = 3 + 2;
                //string teacher = "Eleven";
                //string teacherVip = "Eleven";
                //lock (teacher)
                //{
                //}
                //lock (teacherVip)
                //{
                //}
                //lock (m) { }//值类型不能lock
                lock (btnThreadCore_Click_Lock)//lock后的方法块,任意时刻只有一个线程可以进入  
                //只能锁引用类型,占用这个引用链接   不要用string 因为享元  
                {   //这里就是单线程
                    this.TotalCount += 1;
                    TotalCountIn += 1;
                    this.IntList.Add(newI);
                }
                //private  防止外面也去lock   static 全场唯一  readonly不要改动  object表示引用
                //private static readonly object btnThreadCore_Click_Lock = new object();
                //lock (this)
                //{
                //    //this form1的实例  每次实例化是不同的锁,同一个实例是相同的锁
                //    //private  readonly object btnThreadCore_Click_Lock = new object();
                //    //但是这个实例别人也能访问到,别人也能锁定
                //}
                //Monitor.Enter(btnThreadCore_Click_Lock);
                //Monitor.Exit(btnThreadCore_Click_Lock);

            }));
        }
        Task.WaitAll(taskList.ToArray());
        Console.WriteLine(this.TotalCount);
        Console.WriteLine(TotalCountIn);
        Console.WriteLine(this.IntList.Count());
        #endregion
    }
    //通过遍历去查询出错的信息
    catch (AggregateException aex)
    {
        foreach (var item in aex.InnerExceptions)
        {
            Console.WriteLine(item.Message);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.WriteLine($"=====================ThreadCode 结束【{Thread.CurrentThread.ManagedThreadId.ToString("00")}】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}=====================");
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值