c#中task与thread区别及其使用的方法示例

 更新时间:2022年02月14日 10:23:36   作者:looper.zhuo  
本文主要介绍了c#中task与thread区别及其使用的方法示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

1.什么是thread

当我们提及多线程的时候会想到thread和threadpool,这都是异步操作,threadpool其实就是thread的集合,具有很多优势,不过在任务多的时候全局队列会存在竞争而消耗资源。thread默认为前台线程,主程序必须等线程跑完才会关闭,而threadpool相反。

总结:threadpool确实比thread性能优,但是两者都没有很好的api区控制,如果线程执行无响应就只能等待结束,从而诞生了task任务。

2.什么是task

 task简单地看就是任务,那和thread有什么区别呢?Task的背后的实现也是使用了线程池线程,但它的性能优于ThreadPoll,因为它使用的不是线程池的全局队列,而是使用的本地队列,使线程之间的资源竞争减少。同时Task提供了丰富的API来管理线程、控制。但是相对前面的两种耗内存,Task依赖于CPU对于多核的CPU性能远超前两者,单核的CPU三者的性能没什么差别。

3.创建一个task任务有两种模式:

1.使用factory创建会直接执行,使用new创建不会执行,必须等到start启动之后才执行。

​ public void test()
        {
            var testTask = new Task(() =>
            {
                Console.WriteLine("task start");
            });
            testTask.Start();
            var factoryTeak = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("factory task start");
            });
        }
 
​

2.我们来看看task的生命周期

​var testTask = new Task(() =>
            {
                Console.WriteLine("task start");
                System.Threading.Thread.Sleep(2000);
            });
            Console.WriteLine(testTask.Status);
            testTask.Start();
            Console.WriteLine(testTask.Status);
            Console.WriteLine(testTask.Status);         
            testTask.Wait();
            Console.WriteLine(testTask.Status);
            Console.WriteLine(testTask.Status);
 
​

输出结果:

Created
task start
Running
Running
RanToCompletion
RanToCompletion

可以看出task确实是异步执行,并且wait很好地控制了task。

3.下面演示几个控制task的方法

     var testTask = new Task(() =>
            {
                Console.WriteLine("task start");
                System.Threading.Thread.Sleep(2000);
            });
            testTask.Start();
            testTask.Wait();
 
var testTask = new Task(() =>
            {
               Console.WriteLine("task start");
               System.Threading.Thread.Sleep(2000);
            });
            testTask.Start();
var factoryTeak = Task.Factory.StartNew(() =>
               {                 
                  Console.WriteLine("factory task start");
               });
              Task.WaitAll(testTask, factoryTeak);
              Console.WriteLine("end");
 
​
 var testTask = new Task(() =>
            {
                Console.WriteLine("task start");
                System.Threading.Thread.Sleep(2000);
            });
            testTask.Start();
 var factoryTeak = Task.Factory.StartNew(() =>
               {                  
                  Console.WriteLine("factory task start");
                });
                Task.WaitAny(testTask, factoryTeak);
                Console.WriteLine("end");

通过wait()对单个task进行等待,Task.waitall()对多个task进行等待,waitany()执行任意一个task就往下继续执行。

4.task的回调执行

  var testTask = new Task(() =>
            {
                Console.WriteLine("task start");
                System.Threading.Thread.Sleep(2000);
            });
            testTask.Start();
            var resultTest = testTask.ContinueWith<string>((Task) => {
                Console.WriteLine("testTask end");
                return "end";
            });
            Console.WriteLine(resultTest.Result);

5.task的取消

首先创建一个取消task的令牌的实例,在不启动task直接取消:

var tokenSource = new CancellationTokenSource();//创建取消task实例
            var testTask = new Task(() =>
            {
                for (int i = 0; i < 6; i++) {
                    System.Threading.Thread.Sleep(1000);
                }               
            },tokenSource.Token);
            Console.WriteLine(testTask.Status);
            tokenSource.Token.Register(()=> {
                Console.WriteLine("task is to cancel");
            });
            tokenSource.Cancel();
            Console.WriteLine(testTask.Status);

 输出结果:

Created
task is to cancel
Canceled

如果task启动了真的取消了task?

  var tokenSource = new CancellationTokenSource();//创建取消task实例
            var testTask = new Task(() =>
            {
                for (int i = 0; i <6; i++) {
                    System.Threading.Thread.Sleep(1000);
                }               
            },tokenSource.Token);
            Console.WriteLine(testTask.Status);
            testTask.Start();
            Console.WriteLine(testTask.Status);
            tokenSource.Token.Register(()=> {
                Console.WriteLine("task is to cancel");
            });
            tokenSource.Cancel();
            Console.WriteLine(testTask.Status);
            for (int i = 0; i < 10; i++)
            {
                System.Threading.Thread.Sleep(1000);
                Console.WriteLine(testTask.Status);
            }

输出结果:

Created
WaitingToRun
task is to cancel
Running
Running
Running
Running
Running
Running
RanToCompletion
RanToCompletion
RanToCompletion
RanToCompletion
RanToCompletion

 可以看出其实并没有取消task,此时task还在继续跑。

6.task的嵌套

  var parentTask = new Task(()=> {
                var childTask = new Task(() =>{
                    System.Threading.Thread.Sleep(2000);
                    Console.WriteLine("childTask to start");
                });
                childTask.Start();
                Console.WriteLine("parentTask to start");
            });
            parentTask.Start();
            parentTask.Wait();
            Console.WriteLine("end");

此时为普通关联,父task和子task没影响

  var parentTask = new Task(()=> {
                var childTask = new Task(() =>{
                    System.Threading.Thread.Sleep(2000);
                    Console.WriteLine("childTask to start");
                }, TaskCreationOptions.AttachedToParent);
                childTask.Start();
                Console.WriteLine("parentTask to start");
            } );
            parentTask.Start();
            parentTask.Wait();
            Console.WriteLine("end");

此时为父task和子task关联,wait会一直等待父子task执行完。

6.task死锁的问题

我们可以设置最大等待时间,如果超过了等待时间,就不再等待,下面我们来修改代码,设置最大等待时间为5秒(项目中可以根据实际情况设置),如果超过5秒就输出哪个任务出错了

7.对Spinlock的使用

举例来说Parallel.for和Parallel.foreach是线程不安全的,有可能达不到你的预期,此时就需要加锁来解决此问题,我们可以加lock和spinlock(自旋锁)来解决

            SpinLock slock = new SpinLock(false);
            var testLock= new object();
            long sum1 = 0;
            long sum2 = 0;
            long sum3 = 0;
            Parallel.For(0, 100000, i =>
            {
                sum1 += i;
            });
 
            Parallel.For(0, 100000, i =>
            {
                bool lockTaken = false;
                try
                {
                    slock.Enter(ref lockTaken);
                    sum2 += i;
                }
                finally
                {
                    if (lockTaken)
                        slock.Exit(false);
                }
            });
            Parallel.For(0, 100000, i =>
            {
                lock(testLock)
                {
                    sum3 += i;
                };
            });
            Console.WriteLine("Num1的值为:{0}", sum1);
            Console.WriteLine("Num2的值为:{0}", sum2);
            Console.WriteLine("Num3的值为:{0}", sum3);

输出结果:

Num1的值为:1660913202
Num2的值为:4999950000
Num3的值为:4999950000

Num1的值为:2754493646
Num2的值为:4999950000
Num3的值为:4999950000

Num1的值为:4999950000
Num2的值为:4999950000
Num3的值为:4999950000

最后看看threadpoll和task的结构图:

threadpool:

 task:

 

相关文章

  • C#常用排序方式总结

    C#常用排序方式总结

    在最近的项目中经常会对C#中的数据进行排序,对于基本数据类型,其排序方式比较简单,只需要调用内置算法即可实现,但对于自定义数据类型以及自定义排序规则的情况实现起来就比较麻烦,所以在本文章中将详细介绍一下在中C#中如何对数据进行排序,需要的朋友可以参考下
    2024-01-01
  • C#线程队列用法实例分析

    C#线程队列用法实例分析

    这篇文章主要介绍了C#线程队列用法,以实例形式分析了C#线程队列的创建、运行、等待、结束等操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • C#基于TCP实现简单游戏客户端的完整实例

    C#基于TCP实现简单游戏客户端的完整实例

    这篇文章主要给大家介绍了关于C#基于TCP实现简单游戏客户端的相关资料,通过本文介绍的方法可以直接实现游戏客户端,是个非常适合学习的实例需要的朋友可以参考下
    2021-11-11
  • c#汉诺塔的递归算法与解析

    c#汉诺塔的递归算法与解析

    c#汉诺塔的递归算法与解析,需要的朋友可以参考一下
    2013-03-03
  • C#使用HttpWebRequest与HttpWebResponse模拟用户登录

    C#使用HttpWebRequest与HttpWebResponse模拟用户登录

    这篇文章主要为大家详细介绍了C#使用HttpWebRequest与HttpWebResponse模拟用户登录,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 使用VS2010 C#开发ActiveX控件(下),完整代码打包下载

    使用VS2010 C#开发ActiveX控件(下),完整代码打包下载

    我们介绍了开发、打包、发布、使用ActiveX控件的全过程。在演示程序中,我们没有调用串口通信和读卡器Dll程序,由于我们读卡器的原始Dll是使用其它语言进行开发的,对C#来说,是非托管代码,因此我们还需要在代码级别进行非托管代码的安全性设置
    2011-05-05
  • C# SQLite执行效率的优化教程

    C# SQLite执行效率的优化教程

    这篇文章主要给大家介绍了关于C# SQLite执行效率优化的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C# SQLite具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-06-06
  • C#实现多个计时器记录不同定时时间

    C#实现多个计时器记录不同定时时间

    这篇文章主要为大家详细介绍了C#实现多个计时器记录不同定时时间,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • c# for循环中创建线程执行问题

    c# for循环中创建线程执行问题

    这篇文章主要介绍了有关c# for循环中创建线程执行问题,下面文章将将以举例的方式展开for循环中创建线程执行问题的内容,需要的朋友可以参考一下,希望对你有所帮助
    2021-11-11
  • C# Razor语法规则

    C# Razor语法规则

    这篇文章介绍了C# Razor的语法规则,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-01-01

最新评论