多线程
多线程
多线程特点:线程是计算机资源
Thread
来自于System.Threading的一个密封类,他是在.NET Framorework1.0时代出现的,在c#中用来操作计算机资源线程的一个帮助类库
{
{
ParameterizedThreadStart parameterizedThreadStart = new ParameterizedThreadStart((oInstacnce) =>
{
Debug.WriteLine($"****************ParameterizedThreadStart {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString(" HH:mm:ss.fff")}***************");
});
Thread thread = new Thread(parameterizedThreadStart);
thread.Start();//开启了一个新的线程;
}
{
ThreadStart threadStart = new ThreadStart(() =>
{
this.DoSomething("Richard");
});
Thread thread = new Thread(threadStart);
thread.Start();//开启了一个新的线程;
}
}
{
Thread thread = new Thread(() =>
{
Thread.Sleep(5000);
this.DoSomething("Richard");
});
thread.Suspend(); //1.表示线程暂停;---并不能马上停止下来;
thread.Resume(); //2.线程恢复执行
thread.Abort(); //3.线程停止--子线程对外抛出了一个异常; 线程是无法从外部去终止的;
Thread.ResetAbort();//4.停止的线程继续去执行
//1.线程等待的:ThreadState有多种状态;如果线程停止了,状态会修改;
while (thread.ThreadState != System.Threading.ThreadState.Stopped) //如果线程没有停止;
{
Thread.Sleep(500); //当前休息500ms 不消耗计算机资源的
}
//2.自己支持的线程等待:
thread.Join();//等待线程中的内容执行完毕;继续往后;
thread.Join(500);//等待500ms,过时不候;
thread.Join(TimeSpan.FromMilliseconds(500));//等待500ms,过时不候;
thread.IsBackground = true;// 是后台线程:程序强制关掉,线程也就随之消失了;
thread.IsBackground = false; //是前台线程:程序强制关掉,线程会等待,内部的行为执行完毕,然后才结束;
thread.Start();
}
{
Thread thread = new Thread(() =>
{
this.DoSomething("Richard");
});
// 线程的优先级最高
thread.Priority = ThreadPriority.Highest;
Thread thread1 = new Thread(() =>
{
this.DoSomething("Richard");
});
// 线程的优先级最低
thread1.Priority = ThreadPriority.Lowest;
thread.Start();
thread1.Start();//线程开启后,根据优先级,来执行;---设置优先级只是提高了他被有限执行的概率;
}
//1.有两个动作: 两个委托; 2.必须是多线程执行 3.要求两个委托顺序;
{
ThreadStart threadStart = new ThreadStart(() =>
{
this.DoSomething("Richard");
});
Action action = () =>
{
this.DoSomething("Richard01");
};
//Thread thread = new Thread(threadStart);
//thread.Start();
//Thread thread1 = new Thread(() =>
//{
// action.Invoke();
//});
//thread1.Start();
this.CallBackThread(threadStart, action);//多线程执行两个行为,让两个行为具有顺序之分;
}
/// <summary>
/// 通过Thread扩展封装做到了,多线程执行两个行为,让两个行为具有顺序之分;
/// </summary>
/// <param name="threadStart"></param>
/// <param name="action"></param>
private void CallBackThread(ThreadStart threadStart, Action action)
{
Thread thread = new Thread(() =>
{
threadStart.Invoke();
action.Invoke();
});
thread.Start();
}
//如果有一个带返回值的委托,需要让你多多线程来执行:
{
//希望这个委托能够做到异步执行;
//既想要得到结果,有想多线程执行---做不到;
//
Func<int> func = () =>
{
Thread.Sleep(5000);
return DateTime.Now.Year;
};
//func.BeginInvoke();///.NET Core 中已经不支持了;
//int iResult = this.CallBackFunc<int>(func);
Func<int> func1 = this.CallBackFunc<int>(func);//这一步不会阻塞界面;
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
Debug.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
int iResult = func1.Invoke(); //在这里可以得到结果;
//
}
/// <summary>
/// 多线程执行带有返回值的委托;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
private Func<T> CallBackFunc<T>(Func<T> func)
{
T t = default(T);
ThreadStart threadStart = new ThreadStart(() =>
{
t = func.Invoke();
});
Thread thread = new Thread(threadStart);
thread.Start();
return new Func<T>(() =>
{
thread.Join();//等待thread执行完成;
return t;
});
}
ThreadPool
.NET Framework2.0时代:出现了一个线程池ThreadPool:是一种池化思想,相当于是在池子中,有线程存在;如果需要使用线程;就可以直接到线程池中去获取直接使用,如果使用完毕,在自动的回放到线程池中去;
{
WaitCallback waitCallback = o =>
{
this.DoSomething("Richardd");
};
ThreadPool.QueueUserWorkItem(waitCallback, "1231345");
}
{
ManualResetEvent resetEvent = new ManualResetEvent(false); //默认为False
ThreadPool.QueueUserWorkItem(o =>
{
this.DoSomething(o.ToString());
resetEvent.Set();
}, "Richard");
{
//在这里做一些其他的的事情;
Debug.WriteLine("123456");
Debug.WriteLine("123456");
Debug.WriteLine("123456");
}
resetEvent.WaitOne();//主线程等待; 等到resetEvent中的一个方法resetEvent.Set();执行: resetEvent.Set()执行了,主线程等待的这个WaitOne()就继续往后执行;
}
提示
不建议大家去这样控制线程数量;因为后面要讲解的Task Prallel async await 他们的线程都是来自于线程池的;
如果通过SetMinThreads/SetMaxThreads来设置线程的数量;这个数量访问是在当前进程是全局的;
{
{
int workerThreads = 4;
int completionPortThreads = 4;
ThreadPool.SetMinThreads(workerThreads, completionPortThreads);
}
{
int workerThreads = 8;
int completionPortThreads = 8;
ThreadPool.SetMaxThreads(workerThreads, completionPortThreads);
}
{
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
Debug.WriteLine($"当前进程最小的工作线程数量:{workerThreads}");
Debug.WriteLine($"当前进程最小的IO线程数量:{completionPortThreads}");
}
{
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
Debug.WriteLine($"当前进程最大的工作线程数量:{workerThreads}");
Debug.WriteLine($"当前进程最大的IO线程数量:{completionPortThreads}");
}
}
Async
{
Debug.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
for (int i = 0; i < 5; i++)
{
DoSomething("kulala");
}
Debug.WriteLine($"****************btnSync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
private void DoSomething(string name)
{
Debug.WriteLine($"****************DoSomething Start {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
long lResult = 0;
for (int i = 0; i < 1000_000_000; i++)
{
lResult += i;
}
Thread.Sleep(2000);
Debug.WriteLine($"****************DoSomething End {name} {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************");
}
异步方法:
{
Debug.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
#region 委托异步调用
//在ASP.NET Core的年代:BeginInvoke不再支持了;如果想要看看这个,可以参考第14期;
//Action<string> action = this.DoSomething;
//AsyncCallback asyncCallback = null;
//action.BeginInvoke(" Richard ", asyncCallback, "Object");
#endregion
//Task开启了一个线程
for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
DoSomething("kulala");
});
}
Debug.WriteLine($"****************btnAsyncAdvanced_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
Task
{
{
Task task = new Task(new Action(() =>
{
Debug.WriteLine("欢迎大家来到.NET进阶学习");
this.DoSomething("Richard");
}));
task.Start();//线程开启了
}
{
Task.Run(() =>
{
this.DoSomething("Richard");
});
Task.Run<int>(() =>
{
return DateTime.Now.Year;
});
}
{
TaskFactory factory = Task.Factory;
factory.StartNew(() =>
{
this.DoSomething("一意");
});
}
{
TaskFactory factory = new TaskFactory();
Task<int> tTask = factory.StartNew<int>(() => DateTime.Now.Year);
}
}
{
Task task = new Task(() =>
{
Debug.WriteLine($"****************task开始了: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
Task task1 = new Task(() =>
{
Debug.WriteLine($"****************task1: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
Thread.Sleep(1000);
Debug.WriteLine("我是task1线程");
});
Task task2 = new Task(() =>
{
Debug.WriteLine($"****************task2: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
Thread.Sleep(1000);
Debug.WriteLine("我是task2线程");
});
task1.Start();
task2.Start();
//task1.Wait();
//task2.Wait();
Debug.WriteLine($"****************task: {Thread.CurrentThread.ManagedThreadId.ToString("00")} ***************");
});
task.Start();//线程启动了
task.Wait(); //单个线程的等待;等待task 内部的内容执行完毕,这里会卡顿界面;是主线程等待;
// task.Wait();//等待执行完成:
task.Wait(TimeSpan.FromMilliseconds(1100));
task.Wait(1000);//限时等待;过时不候
// Thread thread = null;
//thread.Abort();//线程停止;
//thread.Start();
//thread.IsBackground = true;//后台线程:进程结束,线程随之消失
//thread.IsBackground = false;//前台线程:进程结束,线程把内部需要执行的动作执行完毕,然后消失
}
//TaskCreationOptions.PreferFairness 相对来说比较公平执行的:如果是先申请的线程,就会优先执行;
{
Task task1 = new Task(() =>
{
}, TaskCreationOptions.PreferFairness);
Task task2 = new Task(() =>
{
}, TaskCreationOptions.PreferFairness);
}
{
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Thread.Sleep(3000);//主线程执行到这儿会卡顿等待;等待3000ms后继续往后;
stopwatch.Stop();
Debug.WriteLine($"Thread.Sleep(3000):{stopwatch.ElapsedMilliseconds}");
}
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
//回调:Delay一般和ContinueWith配合使用;
//不卡顿界面:3000ms以后,去执行一段业务逻辑:执行的动作就是ContinueWith内部的委托;ContinueWith内部的执行有可能是一个全新的线程去执行,也有可能是主线程去执行;
Task.Delay(3000).ContinueWith(t =>
{
Debug.WriteLine($"****************Delay || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
stopwatch.Stop();
Debug.WriteLine($"Task.Delay(3000):{stopwatch.ElapsedMilliseconds}");
});//一般情况下,这个Delay 是等待3000ms继续做点什么---或者说延迟3000ms后做点什么;
}
}
提示
有一个列表数据:有可能是来自于第三方接口,有可能是来自于缓存,也有可能是来自于数据库,查询的时候,我们不确定;
常规玩法: 先找缓存,如果有数据,直接返回了,如果缓存没有--可能要去查询数据库,如果数据库有数据,直接返回,如果没有---查询第三方接口;
多线程:同时开启三个线程,同时去查询三个地方的数据,只要是有一个地方的数据查询到了,只要是有一个地方的数据找到了,其他的两个线程我们就不管了;直接把找到的数据返回给前端就可以了;提示
如果有一个首页,首页中包含了很多功能:考勤信息,年度top10,季度top10,公告,通知;
在主页中:要加载主页-这些信息都需要查询出来: 而且这些信息都是来自于不同的地方,有的来自于接口,有的来自于缓存有的都来于数据库: 有几个块信息,就开启几个线程,同时分别去各自的地方进行查询各自的数据;可以在后台等待所有的子线程执行结束;拿到结果、组件一个大的复杂实体对象,传递给视图,通过视图做绑定;--让查询并发执行: 但是这里如果是使用C#开发,不做前后端分离的话,可以考虑这种,可以提高性能;
现在更多的时候,可能是使用异步Ajax来完成---用户体验会更好; 资源会有所浪费,但是性能可以提高;{ { List<Task> taskList = new List<Task>(); TaskFactory factory = new TaskFactory(); taskList.Add(factory.StartNew(obj => Coding("嘟嘟", "权限的数据库设计"), "嘟嘟")); taskList.Add(factory.StartNew(obj => Coding("年轻人不讲武德", "WeChat接口对接"), "年轻人不讲武德")); taskList.Add(factory.StartNew(obj => Coding("闻", "脚手架框架搭建"), "闻")); taskList.Add(factory.StartNew(obj => Coding("超越", "ABPVNetxt框架搭建"), "超越")); taskList.Add(factory.StartNew(obj => Coding("角印", "编写Webapi"), "角印")); { //相当于是一个回调;主线程执行的时候,这里是不卡段界面的;当taskList集合中的某一个线程执行结束语了;就触发后面委托中的动作;---不卡顿界面--用户体验就更好 factory.ContinueWhenAny(taskList.ToArray(), ts => { Debug.WriteLine($"{ts.AsyncState}同学开发完毕,Richard老师开始准备环境。。。"); }); // } { factory.ContinueWhenAll(taskList.ToArray(), ts => { Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!"); }); } { //Task.WaitAny--等待几个线程中的某一个线程执行结束;---主线程会等待-- - 会卡顿界面;一直到某一个线程执行结束后,才往后执行;--体验不好 Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行; Debug.WriteLine("xxxx同学开发完毕,Richard老师开始准备环境。。。"); } { //Task.WaitAll--等待几个线程都执行结束;---主线程会等待-- 一直到所有的线程执行结束,才往后执行;- 会卡顿界面;--体验不好 Task.WaitAny(taskList.ToArray());//主线程等待,其中某一个线程执行结束,然后继续往后执行; Task.WaitAll(taskList.ToArray()); Debug.WriteLine($"所有人开发完毕,我们一起庆祝一下,一起吃个饭!"); } List<Action> actions = new List<Action>(); actions.Add(() => { }); actions.Add(() => { }); actions.Add(() => { }); actions.Add(() => { }); actions.Add(() => { }); actions.Add(() => { }); actions.Add(() => { }); ParallelOptions options = new ParallelOptions(); options.MaxDegreeOfParallelism = 2; //下面在开启线程执行委托的时候,最多开启2个线程; Parallel.Invoke(options,actions.ToArray()); //会开启四个线程分别去执行; //如果想要限制线程数量 } Debug.WriteLine($"****************btnTask_Click End || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); }
{
Debug.WriteLine($"****************TsakAdvanced_Click start || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
//一、多线程中的异常情况
//1.你们在开发中,如果要捕捉异常---普通方法--try-catch
//2.多线程中,如果发生异常,使用try-catch包裹,捕捉不到异常
//3.异常去哪儿了呢? 异常肯定是被吞掉了
//4.多线程中,如果要捕捉异常---怎么做?
//5.多线程中,如果要捕捉异常,需要设置主线程等待子线程执行结束;可以捕捉到异常
//6.多线程内部发生异常后,抛出的异常类型是:system.AggregateException(多线程的异常类型)
//7.如果(try-catch--catch)给定多个异常类型类匹配,多线程中,异常之后,有限配具体,如果没有具体,再匹配抽象
{
try
{
{
//Task task = Task.Run(() =>
// {
// int i = 0;
// int j = 10;
// int k = j / i; //尝试除以0 会异常
// });
//List<Task> tasks = new List<Task>();
//tasks.Add(task);
//Task.WaitAll(tasks.ToArray());
}
List<Task> tasklist = new List<Task>();
for (int i = 0; i < 20; i++)
{
string keywork = $"TsakAdvanced_Click_{i}";
tasklist.Add(Task.Run(() =>
{
Thread.Sleep(new Random().Next(50, 100));
if (keywork == "TsakAdvanced_Click_6")
{
throw new Exception("TsakAdvanced_Click_6");
}
else if (keywork == "TsakAdvanced_Click_9")
{
throw new Exception("TsakAdvanced_Click_9");
}
else if (keywork == "TsakAdvanced_Click_12")
{
throw new Exception("TsakAdvanced_Click_12");
}
}));
}
Task.WaitAll(tasklist.ToArray());
}
catch (AggregateException aex) //具体
{
Debug.WriteLine(aex.Message);
foreach (var exception in aex.InnerExceptions)
{
Console.WriteLine(exception.Message);
}
}
catch (Exception ex) //父类(一切异常的父类) 抽象
{
Debug.WriteLine(ex.Message);
}
}
//故事、如果三个线程去执行一个业务逻辑体(查询---线程1--执行修改数据库;线程2---执行修改缓存,线程三--执行一个调用接口去修改另外一个服务器上的数据)
//以上这个逻辑体执行过程中,如果有一个线程是异常了;在这个逻辑体中,其实就是一个残缺的--表示整个逻辑就有问题!
//多线程执行的时候,有时候,必须是多个线程都执行成功,才算成功,只要有一个线程异常了,就表示都异常----既然都是异常了,就应该让线程取消;已经异常了,就没哟必须继续往后了
//二、线程取消; 线程是无法从外部取消的(除非关闭进程),只能自己取消自己---只有上帝才能打败上帝;
//1.线程如何自己取消自己呢?----线程自己取消---其实就是向外抛出一个异常了;
//关于Thread/ThreadPool 看过录播的刷个1 否则刷个2
//2.如何取消线程呢?---具体场景中,应该怎么做呢?
//3.标准的线程取消
// a) 实例化一个 CancellationTokenSource
// b) 包含了一个IsCancellationRequested 属性,属性值默认为false
// c) 包含了一个Cancel方法--Cancel 方法如果被执行--CancellationTokenSource 内部的属性值马上---false--true; 且只能从 false--true 不能由true --false
//cts线程取消--看哪个线程跑的慢,如果有一个线程发生了异常了,跑的慢的线程,就会被取消掉(异常掉),如果跑的都比较快的线程--当还没有线程发生异常的时候,这个比较快的线程已经结束了,那么这个结束的线程是无法被取消的;
//4. 当有一个线程发生异常的时候,其他线程就会有三种情况 1.已经结束的线程--不管(管不住); 2.已经正常开始,我可以让你取消,让这线程在结束的时候,抛出异常(取消了);3.还有部分的线程根本都还没有开启:只要有异常的线程,就应该让没有开启的线程不再开启了
{
//Thread thread = null;
//thread.Abort(); //取消线程
}
{
//Task task = Task.Run(() =>
// {
// int i = 0;
// int j = 10;
// int k = j / i; //尝试除以0 会异常
// });
//List<Task> tasks = new List<Task>();
//tasks.Add(task);
//Task.WaitAll(tasks.ToArray());
}
try
{
List<Task> tasks = new List<Task>();
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i < 100; i++)
{
string keywork = $"TsakAdvanced_Click_{i}";
tasks.Add(Task.Run(() =>
{
Thread.Sleep(new Random().Next(10, 300));
//if (cts.IsCancellationRequested == false)
//{
// Debug.WriteLine($" 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 正常开始了");
//}
//else
//{
// Debug.WriteLine($" 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 没有正常开始了");
// //throw new Exception($"{Thread.CurrentThread.ManagedThreadId.ToString("00") }取消了。。。");
//}
cts.Token.ThrowIfCancellationRequested();
try
{
if (keywork == "TsakAdvanced_Click_6")
{
throw new Exception("TsakAdvanced_Click_6");
}
}
catch (Exception)
{
cts.Cancel();
}
cts.Token.ThrowIfCancellationRequested();
//if (cts.IsCancellationRequested == false)
//{
// Debug.WriteLine($" 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 正常结束了。。。");
//}
//else
//{
// Debug.WriteLine($" 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} 没有正常结束了。。。");
// //throw new Exception($"{Thread.CurrentThread.ManagedThreadId.ToString("00") }取消了。。。" );
//}
}, cts.Token)); //有线程发生异常后,还没有开启的线程就不再开启了
}
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException aex)
{
foreach (var exception in aex.InnerExceptions)
{
Debug.WriteLine(exception.Message);
}
}
Debug.WriteLine($"****************TsakAdvanced_Click End || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}
Parallel
{
//如果我需要一次开启多个线程来执行一部分动作呢?
Debug.WriteLine($"****************btnParallel_Click Start || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
{
{
//List<Action> acitonList = new List<Action>();
//acitonList.Add(() => { });
//acitonList.Add(() => { });
//acitonList.Add(() => { });
//Parallel.Invoke(acitonList.ToArray());//也是可以开启线程,可以一次放入很多个委托去执行;
}
//一、Parallel
//1.可以传入多个委托
//2.多个委托中的内容是会开启线程来执行---执行这里的线程有可能是新的线程,也有可能是主线程参与计算的
//3.会阻塞主线程---相当于是主线程等待子线程执行结束
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3;
Parallel.Invoke(options,
() =>
{
Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
this.DoSomething("this is Action 01");
},
() =>
{
Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
this.DoSomething("this is Action 02");
},
() =>
{
Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
this.DoSomething("this is Action 03");
});
}
//二、能不能然他不阻塞界面?包一个Task
{
//Task.Run(() =>
//{
// Parallel.Invoke(
// () =>
// {
// Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// this.DoSomething("this is Action 01");
// },
// () =>
// {
// Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// this.DoSomething("this is Action 02");
// },
// () =>
// {
// Debug.WriteLine($"线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// this.DoSomething("this is Action 03");
// });
//});
}
//三、还不是开启了多个线程去执行委托?有啥作用:--Parallel是基于Task一个封装;
//1.既然是开启多个线程--Parallel.For
//2.如果有一大堆的任务要执行;100个任务---需要多线来执行:100个任务---开启100个线程?--不好
//2.控制线程的数量---Parallel就是可以控制线程的数量,不至于出现线程泛滥的情况
//
{
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3;
Parallel.For(0, 100, options, index =>
{
Debug.WriteLine($"index:{ index} 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
this.DoSomething("this is Action 03");
});
}
{
List<int> intlist = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
//100个
//100个任务: 如果我使用Parallel来开启线程计算;线程会有100个线程来执行--线程数量会过多;
//1.最好能够控制线程数量 100个任务; 限定开启5个线程;控制反正一共就只有五个线程参与计算
//2.相当于5个线程去平摊这100个任务---既开启了多个线程来执行任务---提高性能---且没有过多的开启线程(过多的开启线程会过多的损耗计算机的资源);
ParallelOptions options = new ParallelOptions();
options.MaxDegreeOfParallelism = 3; //会有17个任务,限定了3个线程去执行这17个任务
Parallel.ForEach(intlist, options, s =>
{
Debug.WriteLine($"index:{ s} 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
this.DoSomething("this is Action 03");
});
}
}
Debug.WriteLine($"****************btnParallel_Click End || 线程ID: {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************");
}