在介绍多线程之前,先探讨一下“进程”,“线程”,“句柄”等到底是什么?
进程:计算机概念,程序在运行的时候,记录当前程序对计算机的各种资源的消耗的一种记录。
线程:计算机概念,线程是计算机在执行某一个动作的时候,一个最小的执行流。
句柄:句柄其实就是一个数字--对标与计算机程序中的一个最小单位,每一个组件都有一个句柄。
CPU分片:假如CPU,1s 能处理1000000次计算;把1s内的处理能力再进一步切分, 操作系统去调用执行不同的计算。从宏观角度来讲,一个CPU可以有很多个任务可以去并发执行,而从微观角度来讲,一个CPU在同一时刻,只能为一个任务服务。
有了上面的了解后,我们便开始探讨如何去使用多线程去解决我们日常开发中遇到的问题.
1.同步异步:
同步方法:发起调用,代码执行一行一行的来,按照顺序执行,非常符合我们的开发思维;(线程ID是同一个);
Action<string> action = s=>{ Console.WriteLine(s) ;};
action.Invoke("同步调用");
异步方法:发起调用:没有等待完成,直接进入到下一行,启动一个新的线程来执行动作(线程ID不一样);
Action<string> action = s=>{ Console.WriteLine(s) ;};
action.BeginInvoke(“异步调用”);
注:Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行。Invoke会阻塞主支线程,BeginInvoke只会阻塞主线程,不会阻塞支线程!因此BeginInvoke的异步执行是指相对于支线程异步,而不是相对于主线程异步。
2.线程Thread:是C#语言对计算机资源线程操作的一个封装类
Thread thread = new Thread(new ThreadStart(() => {...}));
thread.Start();//开始
thread.Suspend();//挂起、暂停
thread.Resume(); //恢复暂停的线程
thread.Abort();//停止(对外抛出ThreadAbortException异常)
thread.Join();//主线程等待子线程计算完成;
thread.Join(2000);//等待2000ms
thread.Priority = ThreadPriority.Normal; //线程优先级,其实是提高优先执行的概率,有意外,优先执行并不代表优先结束(千万不要用这个来控制线程的执行顺序)
thread.IsBackground = true;//后台线程;进程关闭,线程也就消失了
thread.IsBackground = false; //前台线程:进程关闭,线程执行完计算才消失
Thread.ResetAbort();//让停止的线程继续允许
3.线程池ThreadPool:
ThreadPool:在.Netframwork2.0基于Thread做了个升级,由于Thread容易滥用,就疯狂开启线程数量造成服务器崩溃,于是在此基础之上利用"池化思想"进行升级为ThreadPool.
池化思想:如果某个对象创建和销毁代价比较高.同时这个对象还可以反复使用的就将其放入一个池子,保存多个这样的对象,需要用的时候从池子里面获取,用完之后不用销毁,放回池子;
1.)分配线程:
WaitCallback waitCallback = o =>
{
Console.WriteLine(o.ToString());
};
ThreadPool.QueueUserWorkItem(waitCallback,"线程池");
2.)设置线程池中线程的数量:设置的最大值,不能小于计算机的逻辑线程数
ThreadPool.SetMinThreads(2, 2);
ThreadPool.SetMaxThreads(4, 4);
ThreadPool.GetMinThreads(out int minworkerThreads, out int mincompletionPortThreads);
ThreadPool.GetMaxThreads(out int maxworkerThreads, out int maxcompletionPortThreads);
3.)线程等待, 观望式:信号量ManualResetEvent
ManualResetEvent 默认要求参数状态false-----关闭-----mre.Set();--打开
ManualResetEvent 状态参数true----打开---mre.Reset();-关闭
ManualResetEvent mre = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(o =>{
Threa.Sleep(2000);
mre .Set();
});
mre.WaitOne();//只要是mre状态编程true,就继续往后执行;
4.任务Task
1.)启动任务:
//第一种
Task task = new Task(() => {Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); });
task.Start();
//第二种
Task task = Task.Run(()=>{Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); });
//第三种
TaskFactory taskFactory = Task.Factory;
Task task = taskFactory.StartNew(()=>{Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); });
2.)验证Task分配的任务是来自线程池:
//线程池是单例的,全局唯一的
//Task的线程是源于线程池
ThreadPool.SetMaxThreads(13, 13);
List<int> countlist = new List<int>();
List<Task> tasklist = new List<Task>();
for (int i = 0; i < 100; i++)
{
int k = i;
tasklist.Add(Task.Run(() =>
{
Console.WriteLine($"This is {k} running ThreadId=
{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
Thread.Sleep(2000);
countlist.Add(Thread.CurrentThread.ManagedThreadId);
}));
}
Task.WaitAll(tasklist.ToArray());
Console.WriteLine(countlist.Distinct().Count());
3.)Sleep 和 Delay 的区别:
//Sleep---同步等待--当前线程等待2s 然后继续
Thread.Sleep(2000);
//Delay---异步等待--等待2s后启动新任务
Task task = Task.Delay(2000)
.ContinueWith(t =>
{
stopwatch.Stop();
Console.WriteLine($"Delay耗时{stopwatch.ElapsedMilliseconds}");
Console.WriteLine($"This is ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});
4.)控制Task任务数量:
List<Task> taskList = new List<Task>();
for (int i = 0; i < 100; i++)
{
if (taskList.Where(t => t.Status != TaskStatus.RanToCompletion).Count() >= 20)
{
Task.WaitAny(taskList.ToArray());
taskList = taskList.Where(t => t.Status != TaskStatus.RanToCompletion).ToList();
}
taskList.Add(Task.Factory.StartNew(() =>
{
long o = 121 * 434;
}));
}
5.Parallel
Parallel可以并发执行多个Action 多线程,但在执行的过程中当前操作Parallel的线程也会参与进来;
//Invoke
Parallel.Invoke(()=>{Console.WriteLine("Action1")},()=>{Console.WriteLine("Action2")},()=>{Console.WriteLine("Action3")});
//For
Parallel.For(0, 5, i => Console.WriteLine($"Action{i}"));
//ForEach
Parallel.ForEach(new int[] { 0, 1, 2, 3, 4 }, i => Console.WriteLine($"Action{i}"));
//设置Parallel最大线程控制
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3;
Parallel.For(0, 10, options, i => Console.WriteLine($"Action{i}"));