首页 > 代码库 > 总结:任务、线程和同步
总结:任务、线程和同步
近期又看了一遍《C#高级编程》这本书,想对书中——任务、线程和同步这一章知识点做一个笔记,让以后工作中忘记某个知识点能直接拿来用,在此进行一个总结。
Parallel数据和任务并行
一、Parallel.For
1、用Parallel.For并行运行迭代
static void ParallelFor() { ParallelLoopResult result = Parallel.For(0, 10, item => { Console.WriteLine("{0},任务{1},线程{2}", item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); }); Console.WriteLine("完成:{0}", result.IsCompleted); }
2、利用ParallelLoopState的Break()方法提前停止For循环
static void ParallelForBreak() { ParallelLoopResult result = Parallel.For(0, 10, (item, pls) => { Console.WriteLine("{0},任务{1},线程{2}", item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); if (item > 5) pls.Break(); }); Console.WriteLine("完成:{0}", result.IsCompleted); Console.WriteLine("忽略:{0}", result.LowestBreakIteration); }
3、对每个线程进行初始化
static void ParallelForInit() { ParallelLoopResult result = Parallel.For<string>(0, 20, () => //Func<TLocal>仅对用于执行迭代的每个线程调用一次 { Console.WriteLine("初始化,任务:{0},线程:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId); return string.Format("线程:{0}", Thread.CurrentThread.ManagedThreadId); }, (item, pls, str1) => //Func<long, ParallelLoopState, TLocal, TLocal> 为循环体定义的委托 //第一个参数是循环迭代,第二个参数ParallelLoopState允许停止循环 //第三个参数接收初始化任务返回的值,类型是泛型For参数定义的 { Console.WriteLine("执行中,编号:{0},str1:{1},任务:{2},线程:{3}", item, str1, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); return string.Format("编号:{0}", item); }, (str1) => //Action<TLocal> 这个方法仅对于每个线程调用一次,这是一个线程退出方法 { Console.WriteLine("完成:{0}", str1); }); }
4、取消任务
/// <summary> /// 取消任务 /// </summary> static void ParallelCancel() { CancellationTokenSource cts = new CancellationTokenSource(); //注册一个任务取消完成时的委托 cts.Token.Register(() => { Console.WriteLine("任务已取消"); }); try { ParallelLoopResult result = Parallel.For(0, 10, new ParallelOptions() { CancellationToken = cts.Token }, item => { Console.WriteLine("循环:{0}", item); Thread.Sleep(1000); if (item == 5) cts.Cancel(); }); } catch (OperationCanceledException ex) { Console.WriteLine(ex.Message); } }
二、Parallel.ForEach
1、用Parallel.ForEach进行异步遍历
static void ParallelForeach() { string[] data = http://www.mamicode.com/{ "张三", "李四", "王五", "赵六", "钱七" }; ParallelLoopResult result = Parallel.ForEach(data, item => { Console.WriteLine("值:{0},任务:{1},线程:{2}", item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); }); }
2、利用ParallelLoopState的Break()方法中断ForEach遍历
static void ParallelForeachBreak() { string[] data = http://www.mamicode.com/{ "张三", "李四", "王五", "赵六", "钱七" }; ParallelLoopResult result = Parallel.ForEach(data, (item, pls, index) => { Console.WriteLine("值:{0},索引:{1},任务:{2},线程:{3}", item, index, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); if (item == "王五") pls.Break(); }); }
三、Parallel.Invoke
1、通过Parallel.Invoke()方法调用多个方法,如果多个任务应并行运行,就可以使用Parallel.Invoke方法,它提供了任务并行性模式
static void ParallelInvoke() { Parallel.Invoke(Zhangsan, Lisi); } static void Zhangsan() { Console.WriteLine("张三"); } static void Lisi() { Console.WriteLine("李四"); }
Task任务
一、创建一个任务执行的方法。
static object taskMethodLock = new object(); static void TaskMethod(object title) { lock (taskMethodLock) { Console.WriteLine(title); Console.WriteLine("任务:{0},线程:{1}", Task.CurrentId == null ? -1 : Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Console.WriteLine("线程池:{0}", Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("后台线程:{0}", Thread.CurrentThread.IsBackground); Console.WriteLine(); } }
二、用不同方式创建任务
/// <summary> /// 用不同方式创建任务 /// </summary> static void CreateTask() { //方式1:使用实例化的TaskFactory类 TaskFactory tf = new TaskFactory(); Task task = tf.StartNew(TaskMethod, "使用TaskFactory类开始任务"); //方式2:使用Task类的静态属性Factory Task.Factory.StartNew(TaskMethod, "使用Task类的静态属性Factory开始任务"); //方式3:使用Task类的构造函数 Task task1 = new Task(TaskMethod, "使用Task类的构造函数开始任务"); task1.Start(); }
三、创建同步任务
/// <summary> /// 同步任务 /// </summary> static void SyncTask() { TaskMethod("主线程"); Task task = new Task(TaskMethod, "同步任务"); task.RunSynchronously(); }
四、创建长时间运行的任务
/// <summary> /// 创建长时间运行的任务 /// </summary> static void LongRunTask() { //创建一个新的线程,而不是使用线程池中的线程 Task task = new Task(TaskMethod, "长时间运行任务", TaskCreationOptions.LongRunning); task.Start(); }
五、任务的结果
/// <summary> /// 任务的结果 /// </summary> static void TaskResult() { Task<string> task = new Task<string>((name) => { Console.WriteLine(name); return string.Format("我叫:{0}", name); }, "张三"); task.Start(); Console.WriteLine(task.Result); task.Wait(); }
六、连续任务
/// <summary> /// 连续任务 /// </summary> static void ContinueTask() { Task task1 = new Task(() => { Console.WriteLine("任务开始:{0}", Task.CurrentId); Thread.Sleep(3000); }); //task1结束后会立即执行task2 Task task2 = task1.ContinueWith((task) => { Console.WriteLine("完成任务:", task.Id); Console.WriteLine("当前任务:", Task.CurrentId); Console.WriteLine("执行一些清理工作"); Thread.Sleep(3000); }); task1.Start(); }
七、任务层次结构
/// <summary> /// 父子任务 /// </summary> static void ParentAndChildTask() { Task parent = new Task(ParentTask); parent.Start(); Thread.Sleep(2000); Console.WriteLine(parent.Status); Thread.Sleep(4000); Console.WriteLine(parent.Status); } static void ParentTask() { Console.WriteLine("任务编号:", Task.CurrentId); Task child = new Task(ChildTask); child.Start(); Thread.Sleep(1000); Console.WriteLine("开始子任务"); } static void ChildTask() { Console.WriteLine("子任务"); Thread.Sleep(5000); Console.WriteLine("子任务完成"); }
八、取消任务
//取消任务 static void CancelTask() { CancellationTokenSource cts = new CancellationTokenSource(); cts.Token.Register(() => { Console.WriteLine("任务取消后执行"); }); Task task = new Task(() => { Console.WriteLine("开始任务"); for (int i = 0; i < 100; i++) { CancellationToken token = cts.Token; if (token.IsCancellationRequested) { Console.WriteLine("任务已取消"); token.ThrowIfCancellationRequested(); } Thread.Sleep(100); Console.WriteLine("循环编号:{0}", i); if (i == 5) cts.Cancel(); } }, cts.Token); task.Start(); try { task.Wait(); } catch (AggregateException ex) { Console.WriteLine("异常:{0},{1}", ex.GetType().Name, ex.Message); foreach (var innerException in ex.InnerExceptions) { Console.WriteLine("内部异常:{0},{1}", ex.InnerException.GetType().Name, ex.InnerException.Message); } } }
ThreadPool线程池
static void ThreadPoolDemo() { int workerThreads; int completionPortThreads; ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads); Console.WriteLine("工作线程:{0},IO线程:{1}", workerThreads, completionPortThreads); for (int i = 0; i < 5; i++) { ThreadPool.QueueUserWorkItem(TaskMethod); } } static void TaskMethod(object state) { for (int i = 0; i < 3; i++) { Console.WriteLine("循环:{0},线程:{1}", i, Thread.CurrentThread.ManagedThreadId); } }
Thread类
一、创建一个线程
/// <summary> /// 创建一个线程 /// </summary> static void CreateThread() { Thread thread = new Thread(() => { Console.WriteLine("这是一个线程,{0}", Thread.CurrentThread.ManagedThreadId); }); thread.Start(); Console.WriteLine("这是一个主线程,{0}", Thread.CurrentThread.ManagedThreadId); }
二、给线程传递数据
1、方式1,使用带ParameterizedThreadStart委托参数的Thread构造函数
/// <summary> /// 给线程传递数据(方式1) /// </summary> static void ThreadWithData1() { var data = http://www.mamicode.com/new { Message = "这是一条消息" }; Thread thread = new Thread((state) => { var obj = (dynamic)state; Console.WriteLine(obj.Message); }); thread.Start(data); }
2、方式2,创建一个自定义类,把线程的方法定义为实例方法,这样就可以初始化实例的数据之后,启动线程。
class MyThread { private string message = string.Empty; public MyThread(string message) { this.message = message; } public void ThreadMain() { Console.WriteLine(message); } }
/// <summary> /// 给线程传递数据(方式2) /// </summary> static void ThreadWithData2() { MyThread myThread = new MyThread("这是一条消息"); Thread thread = new Thread(myThread.ThreadMain); thread.Start(); }
三、后台线程
/// <summary> /// 后台线程 /// </summary> static void BackgroundThread() { Thread thread = new Thread(() => { Console.WriteLine("线程开始启动:{0}",Thread.CurrentThread.Name); Thread.Sleep(3000); Console.WriteLine("线程完成启动:{0}", Thread.CurrentThread.Name); }); thread.Name = "MyThread"; thread.IsBackground = true; thread.Start(); }
总结:任务、线程和同步
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。