Task

  • Task用法
  • 阻塞
  • 线程锁
  • 线程异常
  • 线程取消
  • await

Task
 多线程的几种用法大体上都是相似的,首先我们查看Task的定义:
我们可以通过F12看到他的定义
 如果不想一辈子做一个Coder的话,在使用新知识的时候有些东西需要去挖掘,就拿Task来说,我们可以看到一些信息:
 1.Task是一个非静态的类,在使用的时候需要声明。
 2.Task的构造函数是有参数的。
 3.Task需要一个委托来作为参数,这个委托是没有返回值的。
 4.在我们不知道重载是干什么的时候我们可以查看对应参数的定义,比如说:CancellationToken:传播有关应取消操作的通知。可能解释的不是很明确,但是通过查看CancellationToken可以看到,这个参数如果使用需要实例化,而且在使用的时候需要跟System.Threading.CancellationTokenSource相关联;TaskCreationOptions是一个枚举,每种枚举对应一种模式。

 具体的用法:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    internal class ThreadClass
    {
        public ThreadClass()
        {
            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("Param{0}", i);
                Action action = () => this.DoSomething(name);
                Task task = new Task(action);
                task.Start();
                //跟多线程对比
                //ThreadStart threadStart = () => this.DoSomething(name);
                //Thread thread = new Thread(threadStart);
                //thread.Start();
            }
        }
        
        private void DoSomething(string threadName)
        {
            Console.WriteLine("DoSomething start:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);

            Thread.Sleep(1000);
            Console.WriteLine("DoSomething end:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);
        }
    }
}

 TaskFactory:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    internal class ThreadClass
    {
        public ThreadClass()
        {
            TaskFactory taskFactory = new TaskFactory();
            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("Param{0}", i);
                Action action = () => this.DoSomething(name);
                //这句话的效果等同于声明一个参数为action的对象;执行(Start)
                Task task = taskFactory.StartNew(action);

				//还可以作为有参
				Action<object> act = t =>
                {
                     this.TestThread(t.ToString());
                 };
                 Task task = taskFactory.StartNew(act, name);
            }
        }

        private void DoSomething()
        {
            Console.WriteLine("DoSomething:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        }

        private void DoSomething(string threadName)
        {
            Console.WriteLine("DoSomething start:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);

            Thread.Sleep(1000);
            Console.WriteLine("DoSomething end:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);
        }
    }
}

 阻塞(当前线程):

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    internal class ThreadClass
    {
        public ThreadClass()
        {
            TaskFactory taskFactory = new TaskFactory();
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("Param{0}", i);
                Action action = () => this.DoSomething(name);
                Task task = taskFactory.StartNew(action);
                list.Add(task);
            }
			
			//阻塞,直到有一个线程完成
            Task.WaitAny(list.ToArray());
            Console.WriteLine("WaitAny:{0}", Thread.CurrentThread.ManagedThreadId);
			
			//阻塞,直到有所有线程完成
            Task.WaitAll(list.ToArray());
            Console.WriteLine("WaitAll:{0}", Thread.CurrentThread.ManagedThreadId);
        }

        private void DoSomething(string threadName)
        {
            Console.WriteLine("DoSomething start:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);

            Thread.Sleep(1000);
            Console.WriteLine("DoSomething end:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);
        }
    }
}
========================================================================================
输出:
DoSomething start:Param0-5
DoSomething start:Param1-3
DoSomething start:Param2-6
DoSomething start:Param3-9
DoSomething start:Param7-10
DoSomething start:Param6-8
DoSomething start:Param4-4
DoSomething start:Param5-7
DoSomething start:Param8-11
DoSomething end:Param0-5
DoSomething start:Param9-5
WaitAny:1
DoSomething end:Param1-3
DoSomething end:Param2-6
DoSomething end:Param3-9
DoSomething end:Param7-10
DoSomething end:Param6-8
DoSomething end:Param4-4
DoSomething end:Param5-7
DoSomething end:Param8-11
DoSomething end:Param9-5
WaitAll:1

 通过输出我们能看出来WaitAll/WaitAny是在当前线程阻塞,如果是在UI线程上使用的话,会造成卡顿。

 阻塞(新开线程):

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    internal class ThreadClass
    {
        public ThreadClass()
        {
            TaskFactory taskFactory = new TaskFactory();
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("Param{0}", i);
                Action action = () => this.DoSomething(name);
                Task task = taskFactory.StartNew(action);
                list.Add(task);
            }

            taskFactory.ContinueWhenAny(list.ToArray(), t => Console.WriteLine("ContinueWhenAny"));
            Console.WriteLine("Any:{0}", Thread.CurrentThread.ManagedThreadId);
            taskFactory.ContinueWhenAll(list.ToArray(), t => Console.WriteLine("ContinueWhenAll"));
            Console.WriteLine("All:{0}", Thread.CurrentThread.ManagedThreadId);
        }

        private void DoSomething(string threadName)
        {
            Console.WriteLine("DoSomething start:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);

            Thread.Sleep(1000);
            Console.WriteLine("DoSomething end:{1}-{0}", System.Threading.Thread.CurrentThread.ManagedThreadId, threadName);
        }
    }
}
========================================================================================
Any:1
All:1
DoSomething start:Param0-5
DoSomething start:Param1-4
DoSomething start:Param3-9
DoSomething start:Param2-6
DoSomething start:Param7-8
DoSomething start:Param6-3
DoSomething start:Param5-7
DoSomething start:Param4-10
DoSomething start:Param8-11
DoSomething end:Param0-5
ContinueWhenAny
DoSomething start:Param9-5
DoSomething end:Param1-4
DoSomething end:Param3-9
DoSomething end:Param2-6
DoSomething end:Param7-8
DoSomething end:Param6-3
DoSomething end:Param5-7
DoSomething end:Param4-10
DoSomething end:Param8-11
DoSomething end:Param9-5
ContinueWhenAll

 关于参数可以将ContinueWhenAll/ContinueWhenAny对比AsyncCallBack的用法。在输出中我们可以看到ContinueWhenAll/ContinueWhenAny会新开一个线程取执行。

线程锁
 我们在多线程中会碰到一种情况:多个线程同时执行一步操作,就会出现1+1=1的情况。为了避免这种情况的出现,在我们使用多线程的时候,需要使用线程锁,然而线程锁不是随便在哪里使用都可以的。举个例子:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ThreadPractice
{
    class ThreadClass
    {
        public ThreadClass()
        {
            TaskFactory factory = new TaskFactory();
            List<Task> taskList = new List<Task>();
            int count = 0;
            for (int i = 0; i < 100000; i++)
            {
                Action act = () =>
                {
                    count += 1;
                };
                var task = factory.StartNew(act);
                taskList.Add(task);
            }
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine(count);
        }
    }
}
===============================================================================================
输出结果:99940

 如果这是for循环中是主线程在操作的情况下,我们理想的输出结果应该是100000;输出结果为99940是因为有多个线程同时执行了count+=1的操作,就有了之前说的1+1=1的情况。线程锁就是解决这种问题的。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ThreadPractice
{
    class ThreadClass
    {
        private static object _lock = new object();
        public ThreadClass()
        {
            TaskFactory factory = new TaskFactory();
            List<Task> taskList = new List<Task>();
            int count = 0;
            for (int i = 0; i < 100000; i++)
            {
                Action act = () =>
                {
  					lock (_lock)
                    {
                        count += 1;
                    }
                };
                var task = factory.StartNew(act);
                taskList.Add(task);
            }
            Task.WaitAll(taskList.ToArray());
            Console.WriteLine(count);
        }
    }
}
==========================================================================================
输出结果:100000

线程异常

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    class ThreadPractice
    {
        public ThreadPractice()
        {
            TaskFactory taskFactory = new TaskFactory();
            List<Task> listTask = new List<Task>();

            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("name_{0}", i);
                Action<object> act = t =>
                {
                    try
                    {
                        if (t.ToString().Equals("name_2"))
                        {
                            throw new Exception("throw a error(name_2)");
                        }
                        if (t.ToString().Equals("name_5"))
                        {
                            throw new Exception("throw a error(name_5)");
                        }
                        this.TestThread(t.ToString());
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                };
                Task task = taskFactory.StartNew(act, name);
                listTask.Add(task);
            }
            
            Task.WaitAll(listTask.ToArray());
        }
    }
}

线程取消

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    class ThreadPractice
    {
        public ThreadPractice()
        {
            TaskFactory taskFactory = new TaskFactory();
            List<Task> listTask = new List<Task>();
            CancellationTokenSource cts = new CancellationTokenSource();

            for (int i = 0; i < 10; i++)
            {
                var name = string.Format("name_{0}", i);
                Action<object> act = t =>
                {
                    try
                    {
                        if (t.ToString().Equals("name_2"))
                        {
                            throw new Exception("throw a error(name_2)");
                        }
                        if (t.ToString().Equals("name_5"))
                        {
                            throw new Exception("throw a error(name_5)");
                        }
                        if (cts.IsCancellationRequested)
                        {
                            Console.WriteLine("Cancel");
                        }
                        this.TestThread(t.ToString());
                    }
                    catch (Exception e)
                    {
                        cts.Cancel();
                        Console.WriteLine(e.Message);
                        
                    }
                };
                Task task = taskFactory.StartNew(act, name);
                listTask.Add(task);
            }
            
            Task.WaitAll(listTask.ToArray());
        }
    }
}

await

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPractice
{
    internal class ThreadClass
    {
        public ThreadClass()
        {
        	DoSomethingAwait();
        }
        
        //在使用的await的时候需要添加async
        private async void DoSomethingAwait()
        {
            TaskFactory taskFactory = new TaskFactory();
            Console.WriteLine("当前线程:{0}", Thread.CurrentThread.ManagedThreadId);
            Task task = taskFactory.StartNew(() =>
            {
                Console.WriteLine("Task Start_ID:{0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(100);
                Console.WriteLine("Task End_ID:{0}", Thread.CurrentThread.ManagedThreadId);
            });
            await task;
            Console.WriteLine("Func end_ID:{0}", Thread.CurrentThread.ManagedThreadId);
        }
        //但是推荐使用以下
        //调用方法:
        //Task task = DoSomethingTaskAwait();
        //await task;
 		private async Task DoSomethingTaskAwait()
        {
            TaskFactory taskFactory = new TaskFactory();
            Console.WriteLine("当前线程:{0}", Thread.CurrentThread.ManagedThreadId);
            Task task = taskFactory.StartNew(() =>
            {
                Console.WriteLine("Task Start_ID:{0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(100);
                Console.WriteLine("Task End_ID:{0}", Thread.CurrentThread.ManagedThreadId);
            });
            await task;
            Console.WriteLine("Func end_ID:{0}", Thread.CurrentThread.ManagedThreadId);
        }
    }
}
========================================================================================
输出结果:
当前线程:1
Task Start_ID:3
Task End_ID:3
Func end_ID:1

 await在使用的时候需要给方法加async,await作用为阻塞。DoSomethingTaskAwait()和DoSomethingTask所达效果一样为什么推荐使用DoSomethingTaskAwait();因为如果使用无返回值的方法DoSomethingTask(),在调用的时候系统会提醒我们在调用方法的时候,要使用await,因为方法为void类型。但是如果我们将void用Task替换,就不会出现这种警告,而且async和Task使用是是不需要有返回值的。只是将void改为了Task。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值