任务并行
创建并启动任务
1.指定状态对象
static void Main(string[] args)
{
var task = Task.Factory.StartNew(Go,"hello");
task.Wait();
var task2 = Task.Factory.StartNew(state => Go(state), "world");
Console.WriteLine(task2.AsyncState);
task2.Wait();
Console.WriteLine("End");
Console.ReadLine();
}
static void Go(object state)
{
Console.WriteLine(state);
}
2.TaskCreationOptions
可以调整任务的执行方式。
LongRunning:通知调度器为任务指定一个线程
PreferFairness:会使任务调度器的调度顺序尽可能和任务的开始顺序一致
AttachedToParent:创建子任务
3.子任务
当一个任务启动另外一个任务时,可以确定父子任务关系
父任务必须在所有子任务结束了之后才结束。而父任务结束时,子任务中的异常才向上抛出
var task = Task.Factory.StartNew(()=>
{
Console.WriteLine("one");
Task.Factory.StartNew(() =>
{
Console.WriteLine("I am a child");
},TaskCreationOptions.AttachedToParent);
});
等待多个任务
1.等待一个任务,可以使用Wait或者访问Result
2.或者静态方法,Task.WaitAll等待所有任务,Task.WaitAny等待任意一个任务
Task.WaitAll(task,task2);
Task.WaitAny(task, task2);
取消任务
通过在创建任务时传入取消令牌,来取消任务。取消之后,会抛出异常
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(500);
var task = Task.Factory.StartNew(()=>
{
Console.WriteLine("one");
Thread.Sleep(2000);
}, source.Token);
延续任务
1.Continuewith方法将在一个任务执行完毕之后立即执行一个委托
var task = Task.Factory.StartNew(()=>
{
Console.WriteLine("one");
}).ContinueWith(ant=>
{
Console.WriteLine("two");
}).ContinueWith(ant =>
{
Console.WriteLine("three");
});
2.在前面的任务结束、失败、或取消后,延续的任务开始执行。参数是前面任务的引用。可以一直添加延续。
3.默认前导任务和延续会在不同的线程上执行,但是也可以设置为同一线程,需要指定选项TaskContinuationOptions.ExecuteSynchronously
4.使用前导任务的结果
var task = Task.Factory.StartNew(()=>
{
Console.WriteLine("one");
return 1;
}).ContinueWith(ant=>
{
return ant.Result + 1;
}).ContinueWith(ant =>
{
Console.WriteLine(ant.Result + 1);
});
5.延续任务可以查询前导任务的Exception属性来确认前导任务是否执行失败
6.调用Wait可以重新抛出前导任务的异常
7.或者分别为异常和正常的结果指定不同的延续
8.延续任务只有在所有子任务完成之后才会执行,子任务的所有异常都会封送到延续中
9.一般延续任务是无条件运行的,但是可以通过设置来决定延续是否执行。
var task = Task.Factory.StartNew(() =>
{
throw new Exception();
Console.WriteLine("one");
})
.ContinueWith(ant =>
{
Console.WriteLine("two");
},TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith(ant =>
{
Console.WriteLine("three");
});
上面的例子,one不会执行,two也不会执行,three会执行
NotOnRanToCompletion:正常执行
NotOnFaulted:在错误的时候不取消
NotOnCanceled:在取消令牌时不取消
可以用或(|)组合
10.具有多个前导任务的延续任务
WnenAll,WhenAny
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("one");
});
var task2 = Task.Factory.StartNew(() =>
{
Console.WriteLine("two");
});
Task.WhenAll(task,task2).ContinueWith(ant =>
{
Console.WriteLine("three");
});
并发集合
1.ConcurrentStack,ConcurrentQueue,ConcurrentBag都是用链表实现的。List没有并发集合版本。
var d = new ConcurrentDictionary<int, int>();
for (int i = 0; i < 20; i++)
{
d[i] = i;
}
var d1 = new Dictionary<int, int>();
for (int i = 0; i < 20; i++)
{
lock (d1)
{
d1[i] = i;
}
}
2个代码在功能上是等价的,但是在执行速度上是传统的lock语句快。读取不会有什么明显的差异。