一个Task表示一个异步操作,Task的创建和执行都是独立的,因此可以对关联操作的执行拥有完全的控制权。
一:Task的优势
1: Task支持线程的取消、完成、失败通知等交互性操作
2: Task支持线程执行的先后次序
1
2
3
4
5
6
7
8
9 | Task t = new Task(() =>
{
});
t.ContinueWith((task) =>
{
});
t.Start();
|
二:Task的完成状态
任务Task有这样一些属性,让我们查询任务完成时的状态:
1: IsCanceled,因为被取消而完成
2: IsCompleted,成功完成
3: IsFaulted,因为发生异常而完成
1
2
3
4
5
6
7 | 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 无返回值
1
2 | Task task = new Task(() =>{});
task.Start();
|
new Task 有返回值的方式,Task 与 ContinueWith
1
2
3
4
5
6
7
8
9
10 |
Task< int > task = new Task< int >(() => {
return 0;
});
task.ContinueWith(t =>
{
int result = t.Result;
});
task.Start();
|
方式二、使用 TaskMethod 无返回值
1
2 | Task task = new Task(() => TaskMethod( "Task 2" ));
task.Start();
|
方式三、Task.Run
1 | Task task = Task.Run(() => TaskMethod( "Task 3" ));
|
方式四、直接异步的方法
1 | Task.Factory.StartNew(() => TaskMethod( "Task 3" ));
|
方式五、异步
1
2
3
4
5
6
7 | Task.Run(async () =>
{
await Task.Factory.StartNew(() =>
{
});
});
|
Task任务并行
1
2
3
4
5
6
7
8
9
10
11
12
13 | List<Task> taskList = new List<Task>();
taskList.Add(Task.Run(() =>
{
}));
taskList.Add(Task.Run(() =>
{
}));
taskList.Add(Task.Run(() =>
{
}));
|
//主线程阻塞,等待结束
Task.WaitAll(taskList.ToArray());
主线程 Code ....执行
方式三、异步非阻塞
1
2
3
4
5
6
7
8
9
10
11 | Task[] tlist = new Task[] {
Task.Factory.StartNew(() => {
Thread.Sleep(3000);
}),
Task.Factory.StartNew(() => {
Thread.Sleep(90000);
})
};
Task.WhenAny(tlist).ContinueWith((s) => {
return s;
});
|
使用IProgress实现异步编程的进程通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | 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));
}
|
什么是并行
并行是指两个或者多个事件在同一时刻发生
在程序运行中,并行指多个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());
多线程的异常处理
基本原则:不要轻易捕获根异常;
多线程的内部异常不会传播到主线程,应该在内部进行处理,可以通过事件推到主线程来;
应用程序层面可以捕获根异常,做一些记录工作,切不可隐匿异常。
将异常包装成事件推送到主线程,交给主线程处理。
异步编程中,线程之间只要互不影响,考虑同步问题即可。而在并行编程中,则要求多个线程在同一时刻同时运行。
该文章在 2023/9/15 10:59:27 编辑过