/// <summary> /// 执行动作:耗时而已 /// </summary> private void TestThread(string threadName) { Console.WriteLine("TestThread Start Name={2}当前线程的id:{0},当前时间为{1},", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName); ; ; i < ; i++) { sum += i; } //Thread.Sleep(1000); Console.WriteLine("TestThread End Name={2}当前线程的id:{0},当前时间为{1},计算结果{3}", System.Threading.Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), threadName, sum); }
TestThread
同步方法
private void btnSync_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("*********************************btnSync_Click Start*********************************************"); Console.WriteLine("btnSync_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); ; i < ; i++) { string name = string.Format("btnSync_Click_{0}", i); TestThread(name); } watch.Stop(); Console.WriteLine("*********************************btnSync_Click End {0}********************************************", watch.ElapsedMilliseconds); Console.WriteLine(); }
异步调用
异步调用 同步方法会卡界面,异步多线程不会,原因:同步方法占用了UI线程,无法响应其他操作;异步多线程,UI线程不需要等待计算,计算由子线程完成 同步方法慢,只有主线程计算;异步方法快,启动了多个线程同时计算,会占用更多的资源(多线程的调度管理,也是需要消耗资源的) 异步方法的启动和执行时无序,原因:线程的申请是无序获取;不同线程同一个任务的执行速度也不一定相同;
1 Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("*********************************btnAsync_Click Start*********************************************"); Console.WriteLine("btnAsync_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); List<IAsyncResult> asyncResultList = new List<IAsyncResult>(); ; i < ; i++) { string name = string.Format("btnSync_Click_{0}", i); Action<string> act = TestThread; //act.Invoke(name); asyncResultList.Add(act.BeginInvoke(name, null, null)); //Thread.Sleep(1); } watch.Stop(); Console.WriteLine("*********************************btnAsync_Click End {0}********************************************", watch.ElapsedMilliseconds); Console.WriteLine();
等待:
foreach (var item in asyncResultList) { item.AsyncWaitHandle.WaitOne(); } 或者 ) { Thread.Sleep();//主线程等待着 }
共有资源的访问
; private static object IntValueLock = new object();
; i < ; i++) { IntValue++; } Action act = () => { lock (IntValueLock) { IntValue++; Console.WriteLine(IntValue.ToString()); } }; ; i < ; i++) { act.BeginInvoke(null, null); }
多线程 Thread
Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("*********************************btnThreads_Click Start*********************************************"); Console.WriteLine("btnThreads_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); //表示在 System.Threading.Thread 上执行的方法。 包含该线程过程的数据的对象。 ParameterizedThreadStart method = t => TestThread(t.ToString()); List<Thread> threadList = new List<Thread>(); ; i < ; i++) { string name = string.Format("btnSync_Click_{0}", i); Thread thread = new Thread(method);//默认是前台线程,进程取消后,还会完成计算任务 //thread.IsBackground = true;//设置成后台线程,进程取消后,立即结束 thread.Start(name); threadList.Add(thread); } ) { Thread.Sleep();//主线程等待 Console.WriteLine("btnThreads_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); } //foreach (var thread in threadList) //{ // thread.Join();//阻塞调用线程,直到某个线程终止为止。 //} watch.Stop(); Console.WriteLine("*********************************btnThreads_Click End {0}********************************************", watch.ElapsedMilliseconds); Console.WriteLine();
对比委托的beginInvoke的回调,Thread怎么有回调呢?而且IAsyncResult可以获取其结果
// 摘要: // 表示异步操作的状态。 [ComVisible(true)] public interface IAsyncResult { // 摘要: // 获取用户定义的对象,它限定或包含关于异步操作的信息。 // // 返回结果: // 用户定义的对象,它限定或包含关于异步操作的信息。 object AsyncState { get; } // // 摘要: // 获取用于等待异步操作完成的 System.Threading.WaitHandle。 // // 返回结果: // 用于等待异步操作完成的 System.Threading.WaitHandle。 WaitHandle AsyncWaitHandle { get; } // // 摘要: // 获取一个值,该值指示异步操作是否同步完成。 // // 返回结果: // 如果异步操作同步完成,则为 true;否则为 false。 bool CompletedSynchronously { get; } // // 摘要: // 获取一个值,该值指示异步操作是否已完成。 // // 返回结果: // 如果操作完成则为 true,否则为 false。 bool IsCompleted { get; }
IAsyncResult
不带返回值
/// <summary> /// 带回掉和返回值的线程写法 /// </summary> /// <param name="func">执行方法-带参数</param> /// <param name="callback">回调</param> /// <returns></returns> private string ThreadWithCallback(Func<string> func, Action callback) { string result = null; ThreadStart method = new ThreadStart( () => { result = func(); callback(); }); Thread thread = new Thread(method); thread.Start(); thread.Join();//等待线程完成 return result; }
带返回值
/// <summary> /// 带回掉和返回值的线程写法 /// </summary> /// <param name="func">执行方法-带参数</param> /// <param name="callback">回调</param> /// <returns></returns> private string ThreadWithCallback(Func<string> func, Action callback) { string result = null; ThreadStart method = new ThreadStart( () => { result = func(); callback(); }); Thread thread = new Thread(method); thread.Start(); thread.Join();//等待线程完成 return result; }
线程池ThreadPool
Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("*********************************btnThreadPool_Click Start*********************************************"); Console.WriteLine("btnThreadPool_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); ; i < ; i++) { string name = string.Format("btnThreadPool_Click{0}", i); //表示线程池线程要执行的方法 WaitCallback act = t => TestThread(t.ToString()); //将方法排入队列以便执行,并指定包含该方法所用数据的对象。 此方法在有线程池线程变得可用时执行。 //System.Threading.WaitCallback,它表示要执行的方法。 ThreadPool.QueueUserWorkItem(act, name); } watch.Stop(); Console.WriteLine("*********************************btnThreadPool_Click End {0}********************************************", watch.ElapsedMilliseconds); Console.WriteLine();
可以设置数目,这是Thread没有的
ThreadPool.SetMaxThreads(, );//最小也是核数 ThreadPool.SetMinThreads(, ); int workerThreads; int ioThreads; //-----------------------工作线程 和 IO线程 ThreadPool.GetMaxThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("Max worker threads: {0}; Max I/O threads: {1}", workerThreads, ioThreads)); ThreadPool.GetMinThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("Min worker threads: {0}; Min I/O threads: {1}", workerThreads, ioThreads)); ThreadPool.GetAvailableThreads(out workerThreads, out ioThreads); Console.WriteLine(String.Format("Available worker threads: {0}; Available I/O threads: {1}", workerThreads, ioThreads));
信号量--线程安全
// 摘要: // 通知一个或多个正在等待的线程已发生事件。 此类不能被继承。 [ComVisible(true)] public sealed class ManualResetEvent : EventWaitHandle { // 摘要: // 用一个指示是否将初始状态设置为终止的布尔值初始化 System.Threading.ManualResetEvent 类的新实例。 // // 参数: // initialState: // 如果为 true,则将初始状态设置为终止;如果为 false,则将初始状态设置为非终止。 public ManualResetEvent(bool initialState); }
ManualResetEvent
//如果为 true,则将初始状态设置为终止;如果为 false,则将初始状态设置为非终止 ManualResetEvent test = new ManualResetEvent(false); new Action(() => { Thread.Sleep(); test.Set(); }).BeginInvoke(null, null); test.WaitOne();//是无法通过的----非终止状态--线程阻止了就一直等 test.Set();//变成true-----将事件状态设置为终止状态,允许一个或多个等待线程继续。 test.WaitOne();//立即通过的---终止状态---线程阻止结束就继续执行 test.Reset();//重置为false---将事件状态设置为非终止状态,导致线程阻止 test.WaitOne();//是无法通过的
线程--信号量等待
ManualResetEvent test = new ManualResetEvent(false); WaitCallback act = t => { TestThread(t.ToString()); test.Set();//完成一个才为true }; ThreadPool.QueueUserWorkItem(act, "btnThreadPool_Click"); test.WaitOne();
总结:
Thread回收比较慢,ThreadPool回收快,效果要好点。
异步是基于线程池的,但是回收的加上EndInvoke(),不然回收会比较慢.
Task and TaskFactory
private void btnTask_Click(object sender, EventArgs e) { Stopwatch watch = new Stopwatch(); watch.Start(); Console.WriteLine(); Console.WriteLine("*********************************btnTask_Click Start*********************************************"); Console.WriteLine("btnTask_Click当前主线程的id:{0}", Thread.CurrentThread.ManagedThreadId); TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); ; i < ; i++) { string name = string.Format("btnTask_Click{0}", i); Action<object> act = t => TestThread(t.ToString()); Task task = taskFactory.StartNew(act, name); taskList.Add(task); } taskFactory.ContinueWhenAny(taskList.ToArray(), t => { Console.WriteLine("taskFactory.ContinueWhenAny {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine(t.AsyncState); Console.WriteLine(t.IsCompleted); });//这是回调,会等到某个Task完成后执行,不卡当前线程 taskFactory.ContinueWhenAll(taskList.ToArray(), taskArray => { Console.WriteLine("taskFactory.ContinueWhenAll {0}", Thread.CurrentThread.ManagedThreadId); foreach (var item in taskArray) { Console.WriteLine(item.AsyncState); Console.WriteLine(item.IsCompleted); } });//这是回调,会等到全部Task完成后执行,不卡当前线程 //Task.WaitAny(taskList.ToArray());//所在的线程等待 目前在主线程 会等待某个Task的完成 //Console.WriteLine("某个Task都执行完毕了!"); //Task.WaitAll(taskList.ToArray());//所在的线程等待 目前在主线程 会等待全部Task的完成 //Console.WriteLine("所有的Task都执行完毕了!"); watch.Stop(); Console.WriteLine("*********************************btnTask_Click End {0}********************************************", watch.ElapsedMilliseconds); Console.WriteLine(); }
Parallel
// // 摘要: // 尽可能并行执行提供的每个操作。 // // 参数: // actions: // 要执行的 System.Action 数组。 // // 异常: // System.ArgumentNullException: // actions 参数为 null。 // // System.AggregateException: // 当 actions 数组中的任何操作引发异常时引发的异常。 // // System.ArgumentException: // actions数组包含 null 个元素。 public static void Invoke(params Action[] actions); // // 摘要: // 执行所提供的每个操作,而且尽可能并行运行,除非用户取消了操作。 // // 参数: // parallelOptions: // 一个对象,用于配置此操作的行为。 // // actions: // 要执行的操作数组。 // // 异常: // System.OperationCanceledException: // 设置处于 parallelOptions 中的 System.Threading.CancellationToken。 // // System.ArgumentNullException: // actions 参数为 null。-或- 方parallelOptions 参数为 null。 // // System.AggregateException: // 当 actions 数组中的任何操作引发异常时引发的异常。 // // System.ArgumentException: // actions 数组包含 null 元素。 // // System.ObjectDisposedException: // 在 parallelOptions 中与 System.Threading.CancellationToken关联的 System.Threading.CancellationTokenSource // 已被释放。 public static void Invoke(ParallelOptions parallelOptions, params Action[] actions);
public static class Parallel
//就是在Task的基础上封装,多个任务并行计算,其实就是Task + WaitAll,而且主线程也在计算 Parallel.Invoke(() => Console.WriteLine("1 当前线程id={0}", Thread.CurrentThread.ManagedThreadId) , () => Console.WriteLine("2 当前线程id={0}", Thread.CurrentThread.ManagedThreadId) , () => Console.WriteLine("3 当前线程id={0}", Thread.CurrentThread.ManagedThreadId) , () => Console.WriteLine("4 当前线程id={0}", Thread.CurrentThread.ManagedThreadId)); //计算全部完成后,才会进入下一行代码,看上去就是同步编程
Parallel.ForEach/For
Parallel.ForEach<, , , , }, t => { Console.WriteLine("{0} ForEach当前线程id={1}", t, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(); }); Parallel.For(, , t => { Console.WriteLine("{0} For当前线程id={1}", t, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(); });
可设置最大并行数
namespace System.Threading.Tasks { // 摘要: // 存储用于配置 System.Threading.Tasks.Parallel 类的方法的操作的选项。 public class ParallelOptions { // 摘要: // 初始化 System.Threading.Tasks.ParallelOptions 类的新实例。 public ParallelOptions(); // 摘要: // 获取或设置与此 System.Threading.Tasks.ParallelOptions 实例关联的 System.Threading.CancellationToken。 // // 返回结果: // 与此实例关联的标记。 public CancellationToken CancellationToken { get; set; } // // 摘要: // 获取或设置此 ParallelOptions 实例所允许的最大并行度。 // // 返回结果: // 一个表示最大并行度的整数。 // // 异常: // System.ArgumentOutOfRangeException: // 当此 System.Threading.Tasks.ParallelOptions.MaxDegreeOfParallelism 设置为 0 或小于 // -1 的某个值时引发的异常。 public int MaxDegreeOfParallelism { get; set; } // // 摘要: // 获取或设置与此 System.Threading.Tasks.ParallelOptions 实例关联的 System.Threading.Tasks.TaskScheduler。 // 将此属性设置为 null,以指示应使用当前计划程序。 // // 返回结果: // 与此实例关联的任务计划程序。 public TaskScheduler TaskScheduler { get; set; } } }
MaxDegreeOfParallelism
ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = }; Parallel.For(, , options, t => { Console.WriteLine("{0} For当前线程id={1}", t, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(); });
ParallelLoopState
// // 摘要: // 执行 for(在 Visual Basic 中为 For)循环,其中可能会并行运行迭代,而且可以配置循环选项,可以监视和操作循环的状态。 // // 参数: // fromInclusive: // 开始索引(含)。 // // toExclusive: // 结束索引(不含)。 // // parallelOptions: // 一个对象,用于配置此操作的行为。 // // body: // 将为每个迭代调用一次的委托。 // // 返回结果: // 包含有关已完成的循环部分的信息的结构。 // // 异常: // System.OperationCanceledException: // 取消 parallelOptions 参数中的 System.Threading.CancellationToken。 // // System.ArgumentNullException: // body 参数为 null。-或- 方parallelOptions 参数为 null。 // // System.AggregateException: // 包含在所有线程上引发的全部单个异常的异常。 // // System.ObjectDisposedException: // 在 parallelOptions 中与 System.Threading.CancellationToken关联的 System.Threading.CancellationTokenSource // 已被释放。 public static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int, ParallelLoopState> body);
ParallelLoopState
state.Break() + return;
或者 state.Stop()
ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = }; //Parallel.For(0, 100, options, t => //{ // Console.WriteLine("{0} For当前线程id={1}", t, Thread.CurrentThread.ManagedThreadId); // Thread.Sleep(3000); //}); Parallel.For(, , options, (t, state) => { Console.WriteLine("{0} For当前线程id={1}", t, Thread.CurrentThread.ManagedThreadId); state.Break();//循环结束 //state.Stop();//paraller结束计算 return;//带上return才有效 //二者不能同时出现,会异常 Thread.Sleep(); });
多线程的临时变量
Action<int> act = i => { Thread.Sleep(); Console.WriteLine(i); }; ; i < ; i++) { Task.Run(() => act(i));//多线程任务真的执行时,i=10了 //或者 //new Action(() => act(i)).BeginInvoke(null, null); }
解决办法:
Action<int> act = i => { Thread.Sleep(); Console.WriteLine(i); }; ; i < ; i++) { int k = i;//每次循环,声明一个新的变量k Task.Run(() => act(k)); }
多线程的异常处理
TaskFactory taskFactory = new TaskFactory(); List<Task> taskList = new List<Task>(); // 通知 System.Threading.CancellationToken,告知其应被取消。 CancellationTokenSource cts = new CancellationTokenSource(); ; i < ; i++) { string name = string.Format("btnTask_Click{0}", i); Action<object> act = t => { try { if (t.ToString().Equals("btnTask_Click2")) { throw new Exception(string.Format("{0} 执行失败", t)); } if (t.ToString().Equals("btnTask_Click3")) { throw new Exception(string.Format("{0} 执行失败", t)); } Thread.Sleep(); // 获取是否已请求取消此 System.Threading.CancellationTokenSource。 if (!cts.IsCancellationRequested)//IsCancellationRequested 被取消 { Console.WriteLine("{0} 执行成功", t); } else { Console.WriteLine("{0} 被取消", t); } } catch (Exception ex) { // 传达取消请求。 cts.Cancel(); Console.WriteLine("子线程异常 {0}", ex.Message); } }; Task task = taskFactory.StartNew(act, name, cts.Token); taskList.Add(task); } Task.WaitAll(taskList.ToArray());
; i < ; i++) { string name = string.Format("btnSync_Click_{0}", i); Action<string> act = TestThread; //act.Invoke(name); asyncResultList.Add(act.BeginInvoke(name, null, null)); //Thread.Sleep(1); } //EndInvoke()
EndInvoke