C#多线程工具使用笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

留点东西,所有的观点均是自己实践,可能并不是很准确,仅供参考,有错误还望指出!谢谢!

各个类的用法什么的网上一大堆,就不写了。

一、Thread

这个类个人感觉是最接近底层的线程类,提供了许多强大的接口例如挂起,继续,终止等等接口

[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
配合 thread.Abort() 可以实现直接Kill当前线程的效果

优点

可以非常迅速的从系统中申请线程,迅速运行较多的需要并行运行的任务(我的电脑测试出来的是同时2500个左右,多了会内存不够,程序崩溃。)

缺点

申请资源不受管控,一次性获取过多的线程会造成内存不足,程序崩溃等问题。

二、ThreadPool

ThreadPool类相当是给Thread的缺点打了个补丁。他会一次性申请几个线程给程序,当调用线程时就从里面取出一个空闲线程分配出来。当调用的线程运行完后又交还给线程池中。

可以通过 ThreadPool.SetMaxThreads (int workerThreads,int completionPortThreads) 设置线程池线程的默认个数。

优点

弥补了Thread的缺点

缺点

缺点就是 没有了Thread的优点 因为在这个池子机制的管控下,.net是有最小默认工作线程的,比如说我默认线程4个,那我这个时候要跑5个任务,这个时候系统就会等待前4个中的任何一个线程空闲下来才会执行第5个,或者等待0.5秒到1秒钟线程池会再从系统中申请一个线程来给新的任务分配线程,如果任务个数较多,那么对于执行完全部任务的速度将会大大降低。

题外话 写到这我就觉得就尼玛的离谱,好像真的没有完美的工具,但是工具死的,人是活的,合理的通过现有资源来开发出合适的项目才是正确的目标

三、Task

Thread 和 ThreadPool 的升级版,Task开的线程都是基于线程池的,同时他开线程很方便,而且在控制和拓展上提供的功能也比较多。

Task的启动有4种方式,分别是:实例化的方式+Start方法启动、Task.Run()方法启动、TaskFactory.StartNew()方法启动、Task.RunSynchronously() 是同步 启动。

Task下的线程等待和延续主要以下几类:
 
Wait:
  针对单个Task的实例,可以task1.wait进行线程等待(如果主线程执行,则卡主线程)

WaitAny:
  执行的线程等待其中任何一个线程执行完毕即可执行(如果主线程执行,则卡主线程)

WaitAll:
  执行的线程等待其中所有线程执行完毕方可执行(如果主线程执行,则卡主线程)

WhenAny:
   与下面ContinueWith配合执行,当传入的线程中任何一个线程执行完毕,继续执行ContinueWith中的任务(属于开启新线程,不卡主线程)

WhenAll:
  与下面ContinueWith配合执行,当传入的线程中所有线程执行完毕,继续执行ContinueWith中的任务(属于开启新线程,不卡主线程)

ContinueWith:
  和上面WhenAny和WhenAll配合使用

四、TaskFactory

给Task提供的一个工具类,可以方便的使用线程等待,以及创建新线程任务。

taskFactory.StartNew();              //等价于Task.Run()
taskFactory.ContinueWhenAny();      
taskFactory.ContinueWhenAll();     

详情

 TaskFactory taskFactory = new TaskFactory();
                List<Task> taskList = new List<Task>();
                taskList.Add(Task.Run(() => this.Coding("参数1")));
                taskList.Add(taskFactory.StartNew(() => this.Coding("参数2")));
                taskList.Add(Task.Run(() => this.Coding("参数3")));
                taskList.Add(taskFactory.StartNew(() => this.Coding("参数4")));
                taskList.Add(Task.Run(() => this.Coding("参数5")));
 
                //当taskList中执行完任意一个任务时,非阻塞式的回调
                taskFactory.ContinueWhenAny(taskList.ToArray(), t =>
                {
                    Console.WriteLine($"有一个任务执行完成");
                });
 
                //当taskList中执行完所有任务时,非阻塞式的回调
                taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), rArray =>
                {
                    Console.WriteLine($"所有任务执行完成");
                }));

五、async 和 await

这玩意儿语法很反人类呀有木有?但是好处在于挺方便,不需要使用一堆的代码就可以实现不卡主进程的效果。

对比一下不用 await,async和 await,async的差别

首先定义异步请求任务。


        private async Task<int> AsyncFunction(int obj)  //创建async异步任务
        {
            int val;
            await Task.Run(() =>
            {   
                val = 0;
                Console.WriteLine("开始模拟业务请求");
                TaskTestClass._DryRun();
                Console.WriteLine("获取模拟业务请求返回值");
                val = obj;
            });
            return val;
        }

        private Task<int> DfFunction(int obj)  //创建常规异步任务
        {
            return Task<int>.Run(() =>
            {
                int val = 0;
                Console.WriteLine("开始模拟业务请求");
                TaskTestClass._DryRun();
                Console.WriteLine("获取模拟业务请求返回值");
                val = obj;
                return val;
            });
        }


然后创建在调用函数

        //使用 await
        private async void AsyncAwaitTest()
        {
            var taskResult = await AsyncFunction(10); //主线程中同步等待任务执行结果,且不会卡主线程
            this.Title = taskResult.ToString();      //等待任务完成后,主线程执行任务
        }
        
       //不使用 await
        private void AsyncTest()
        {
            TaskFactory taskFactory = new TaskFactory();
            taskFactory.ContinueWhenAny(new Task[] { DfFunction(10) } 
            //开始异步执行AsyncFunction(10)任务等待结果,异步当然也不会卡界面
            , new Action<Task>((inTask) =>
            {   //等待异步任务完成后
                App.Current.Dispatcher.Invoke(() =>  //使用主线程执行任务
                {
                    var taskResult = (inTask as Task<int>).Result;
                    this.Title = taskResult.ToString();
                });
            }));
        }

结论:一样的效果,不一样的代码量,果然还是 await,async 方便
反编译完以后,发现里面有个线程调度的玩意儿,但我没去细看,应该就是这个东西实现的不卡界面的效果,先留个心结在这,有兴趣的时候再去细看。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值