C# Task(任务调度)
参考:https://www.cnblogs.com/zhaoshujie/p/11082753.html
一个Task表示一个异步操作,Task的创建和执行都是独立的,因此可以对关联操作的执行拥有完全的控制权。
一:Task的优势
1: Task支持线程的取消、完成、失败通知等交互性操作
2: Task支持线程执行的先后次序
Task t = new Task(() => { }); t.ContinueWith((task) => { }); t.Start();
二:Task的完成状态
任务Task有这样一些属性,让我们查询任务完成时的状态:
1: IsCanceled,因为被取消而完成
2: IsCompleted,成功完成
3: IsFaulted,因为发生异常而完成
CancellationTokenSource cts = new CancellationTokenSource(); Task<int> t = new Task<int>(() => Add(cts.Token), cts.Token); t.Start(); t.ContinueWith(TaskEnded); //等待按下任意一个键取消任务 Console.ReadKey(); cts.Cancel();
任务Task创建方式
方式一、new Task 无返回值
Task task = new Task(() =>{}); task.Start();
new Task 有返回值的方式,Task 与 ContinueWith
//先执行Task Task<int> task = new Task<int>(() => { return 0; }); //其次执行ContinueWith task.ContinueWith(t => { int result = t.Result; }); task.Start();
方式二、使用 TaskMethod 无返回值
Task task = new Task(() => TaskMethod("Task 2")); task.Start();
方式三、Task.Run
Task task = Task.Run(() => TaskMethod("Task 3"));
方式四、直接异步的方法
Task.Factory.StartNew(() => TaskMethod("Task 3"));
方式五、异步
Task.Run(async () => { await Task.Factory.StartNew(() => { }); });
Task任务并行
List<Task> taskList = new List<Task>(); taskList.Add(Task.Run(() => { })); taskList.Add(Task.Run(() => { })); taskList.Add(Task.Run(() => { }));
//主线程阻塞,等待结束
Task.WaitAll(taskList.ToArray());
主线程 Code ....执行
方式三、异步非阻塞
Task[] tlist = new Task[] { Task.Factory.StartNew(() => { Thread.Sleep(3000); }), Task.Factory.StartNew(() => { Thread.Sleep(90000); }) }; Task.WhenAny(tlist).ContinueWith((s) => { return s; });
使用IProgress实现异步编程的进程通知
private void btnSub_Click(object sender, RoutedEventArgs e) { Task task = Display(); } void DoProcessing(IProgress<int> progress) { if (progress != null) { progress.Report(1); } } async Task Display() { //当前线程 var progress = new Progress<int>(percent => { this.Title = percent.ToString(); }); //线程池线程 await Task.Run(() => DoProcessing(progress)); }
本文来源参考:https://www.cnblogs.com/zhaoshujie/p/11082753.html
什么是并行
并行是指两个或者多个事件在同一时刻发生
在程序运行中,并行指多个CPU核心同时执行不同的任务;对于单核心CPU,严格来说是没有程序并行的。并行是为了提高任务执行效率,更快的获取结果。
与并发的区别
并发是指两个或者多个事件在同一时段发生。
相对于并行,并发强调的是同一时段,是宏观上的同时发生。实际上,同一时刻只有一个任务在被执行,多个任务是分时地交替执行的。并发是为了更合理地分配资源。
实现并行,我们要借助进程和线程。
进程是正在运行的程序的实例。
线程被包含在进程之中,是进程中的实际运作单位。
前台线程和后台线程
.NET把线程分为前台线程和后台线程,两者几乎相同,唯一的区别是,前台线程会阻止进程的正常退出,后台线程则不会。
线程池 ThreadPool
线程的创建和销毁要耗费很多时间,而且过多的线程不仅会浪费内存空间,还会导致线程上下文切换频繁,影响程序性能。为改善这些问题,.NET运行时(CLR)会为每个进程开辟一个全局唯一的线程池来管理其线程。
多线程
1、在执行一个较长时间的任务时,不能阻塞UI界面响应,必须通过后台线程处理;
2、在执行批量计算密集型任务时,采用多线程技术可以提高运行效率;
传统使用的多线程技术有:
Thread & ThreadPool
Timer
BackgroundWorker
Task内部也是对ThreadPool的封装
采用并行编程方法:
Parallel.For(1, 10000, x=>
{
bool b = IsPrimeNumber(x);
Console.WriteLine($"{i}:{b}");
});
//使用并行循环处理数据更新
List<string> lists = new List<string>();
System.Threading.Tasks.Parallel.For(0, lists.Count, (int i) =>
{
string sql = string.Format("update table1 set IsExit =1 where Id='{0}'", lists[i]);
Execute(sql);
});
和Task类似,Parallel类仍然是对ThreadPool的封装。
需要通知一个任务结束,或一个任务等待某个条件进入下一个状态,这就需要用到任务同步的技术。
采用WaitOne来等待
异步编程模型(await、async)
非UI线程不能访问UI控件,可以使用Invoke
多线程环境下的数据安全
private static ConcurrentDictionary<int, string> Dic = new ConcurrentDictionary<int, string>();
//添加操作
Dic.TryAdd(i, i.ToString());
多线程的异常处理
基本原则:不要轻易捕获根异常;
多线程的内部异常不会传播到主线程,应该在内部进行处理,可以通过事件推到主线程来;
应用程序层面可以捕获根异常,做一些记录工作,切不可隐匿异常。
将异常包装成事件推送到主线程,交给主线程处理。
参考:https://www.cnblogs.com/seabluescn/p/12973936.html
异步编程中,线程之间只要互不影响,考虑同步问题即可。而在并行编程中,则要求多个线程在同一时刻同时运行。