**大部分内容来自网上整理
部分来源 作者:释迦苦僧 出处:http://www.cnblogs.com/woxpp/p/3928788.html**
//Task 表示一个类的异步的并发的操作
Task t = Task.Run( () => {
// do something.
} );
t.Wait();//阻塞调用线程直到这个线程完成。可以传入参数控制阻塞时间/
var tasks = new Task[3];
var rnd = new Random();
for (int ctr = 0; ctr <= 2; ctr++)
tasks[ctr] = Task.Run( () => Thread.Sleep(rnd.Next(500, 3000)));
try {
int index = Task.WaitAny(tasks);//其中一个完成就不阻塞,返回完成任务;WaitAll()所有完成才不阻塞
//任务属性Status、IsCanceled、IsCompleted、IsFaulted
foreach (var t in tasks)
Console.WriteLine("Task #{0}: {1}", t.Id, t.Status);
}
catch (AggregateException) {
Console.WriteLine("An exception occurred.");
}
//等待一个或多个任务完成时,则在正在运行的任务引发的任何异常传播调用的线程上 Wait 方法上。
foreach (var t in tasks) {
Console.WriteLine("Task #{0}: {1}", t.Id, t.Status);
if (t.Exception != null) {
foreach (var ex in t.Exception.InnerExceptions)
Console.WriteLine("{0}: {1}", ex.GetType().Name,ex.Message);
}
}
并行迭代 Task.Parallel
使用Parallel.For、Parallel.ForEach Parallel.Invoke TPL会在后台创建System.Threading.Tasks.Task的实例。
Parallel.Invoke 对给定任务实现并行开发
Parallel.For 对固定数目的任务提供循环迭代并行开发
parallel.Foreach 对固定数目的任务提供循环迭代并行开发
Parallel.Invoke(
() =>
{
Task1();
},
Task2,
delegate () { Task3(); console.write('do someting!');});
1、没有固定的顺序,每个Task可能是不同的线程去执行,也可能是相同的;
2、主线程必须等Invoke中的所有方法执行完成后返回才继续向下执行;这样对我们以后设计并行的时候,要考虑每个Task任务尽可能差不多,如果相差很大,比如一个时间非常长,其他都比较短,这样一个线程可能会影响整个任务的性能。
3、这个非常简单就实现了并行,不用我们考虑线程问题。主要Framework已经为我们控制好线程池的问题。
4、Invoke在每次调用都有开销的,不一定并行一定比串行好,要根据实际情况,内核环境多次测试调优才可以。
理解ParallelOptions建议大家异步编程:轻量级线程同步基元对象 讲的非常详细。
主要理解两个参数:
CancellationToken 控制线程的取消
MaxDegreeOfParallelism 设置最大的线程数,有时候可能会跑遍所有的内核,为了提高其他应用程序的稳定性,就要限制参与的内核
// 定义CancellationTokenSource 控制取消
readonly CancellationTokenSource _cts = new CancellationTokenSource();
/// <summary>
/// Invoke方式一 action
/// </summary>
public void Client1()
{
Console.WriteLine("主线程:{0}线程ID : {1};开始{2}", "Client3", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
var po = new ParallelOptions
{
CancellationToken = _cts.Token, // 控制线程取消
MaxDegreeOfParallelism = 3 // 设置最大的线程数3,仔细观察线程ID变化
};
Parallel.Invoke(po, () => Task1("task1"), ()=>Task5(po), Task6);
Console.WriteLine("主线程:{0}线程ID : {1};结束{2}", "Client3", Thread.CurrentThread.ManagedThreadId, DateTime.Now);
}
private void Task1(string data)
{
Thread.Sleep(5000);
Console.WriteLine("任务名:{0}线程ID : {1}", data, Thread.CurrentThread.ManagedThreadId);
}
// 打印数字
private void Task5(ParallelOptions po)
{
Console.WriteLine("进入Task5线程ID : {0}", Thread.CurrentThread.ManagedThreadId);
int i = 0;
while (i < 100)
{
// 判断是否已经取消
if (po.CancellationToken.IsCancellationRequested)
{
Console.WriteLine("已经被取消。");
return;
}
Thread.Sleep(100);
Console.Write(i + " ");
Interlocked.Increment(ref i);
}
}
/// <summary>
/// 10秒后取消
/// </summary>
private void Task6()
{
Console.WriteLine("进入取消任务,Task6线程ID : {0}", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000 * 10);
_cts.Cancel();
Console.WriteLine("发起取消请求...........");
}
Task返回值 Task<TResult>
class Program
{
/* coder:释迦苦僧 */
static void Main(string[] args)
{
Task<List<Product>> tk1 = Task<List<Product>>.Factory.StartNew(() => SetProduct());
Task.WaitAll(tk1);
Console.WriteLine(tk1.Result.Count);
Console.WriteLine(tk1.Result[0].Name);
Console.ReadLine();
}
static List<Product> SetProduct()
{
List<Product> result = new List<Product>();
for (int i = 0; i < 500; i++)
{
Product model = new Product();
model.Name = "Name" + i;
model.SellPrice = i;
model.Category = "Category" + i;
result.Add(model);
}
Console.WriteLine("SetProduct 执行完成");
return result;
}
}
延续串联多个任务
ContinueWith:创建一个目标Task完成时,异步执行的延续程序
class Program
{
/* coder:释迦苦僧 */
static void Main(string[] args)
{
/*创建任务t1*/
Task t1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("执行 t1 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, 2000);
});
/*创建任务t2 t2任务的执行 依赖与t1任务的执行完成*/
Task t2 = t1.ContinueWith((t) =>
{
Console.WriteLine("执行 t2 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, 2000);
});
/*创建任务t3 t3任务的执行 依赖与t2任务的执行完成*/
Task t3 = t2.ContinueWith((t) =>
{
Console.WriteLine("执行 t3 任务");
});
Console.ReadLine();
}
}
TaskContinuationOptions参数,可以控制延续另一个任的任务调度和执行的可选行为。
class Program
{
/* coder:释迦苦僧 */
static void Main(string[] args)
{
/*创建任务t1*/
Task t1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("执行 t1 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, 2000);
throw new Exception("异常");
});
/*创建任务t2 t2任务的执行 依赖与t1任务的执行完成*/
Task t2 = t1.ContinueWith((t) =>
{
Console.WriteLine(t.Status);
Console.WriteLine("执行 t2 任务");
SpinWait.SpinUntil(() =>
{
return false;
}, 2000);
/*定义 TaskContinuationOptions 行为为 NotOnFaulted 在 t1 任务抛出异常后,t1 的任务状态为 Faulted , 则t2 不会执行里面的方法 但是需要注意的是t3任务*/
/*t2在不符合条件时 返回Canceled状态状态让t3任务执行*/
}, TaskContinuationOptions.NotOnFaulted);
/*创建任务t3 t3任务的执行 依赖与t2任务的执行完成*/
/*t2在不符合条件时 返回Canceled状态状态让t3任务执行*/
Task t3 = t2.ContinueWith((t) =>
{
Console.WriteLine(t.Status);
Console.WriteLine("执行 t3 任务");
});
Console.ReadLine();
}
}
TaskContinuationOptions 参数
![这里写图片描述](http://img.blog.csdn.net/20171025104132240?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzcxMjY0MDA=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
Parallel.For,普通的For是一个串行操作,如果说你的for中每条流程都需要执行一个方法,并且这些方法可以并行操作且比较耗时,可采用Parallel.For它会在底层根据硬件线程的运行状况来充分的使用所有的可利用的硬件线程并行处理。
Parallel.For(0, 100, i => { Console.Write(i + "\t"); });
由于并行同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面。
Parallel.forEach,的独到之处就是可以将数据进行分区,每一个小区内实现串行计算,分区采用Partitioner.Create实现。
Parallel.ForEach(Partitioner.Create(0, 3000000), i =>
{
for (int m = i.Item1; m < i.Item2; m++)
{
bag.Add(m);
}
});
其实ForEach和for在本质上是一样的,你在源代码中会发现在底层都是调用一个方法的,而ForEach会在底层中调用for共同的函数之前还会执行其他的一些逻辑,所以这就告诉我们,能用Parallel.For的地方就不要用Parallel.ForEach,其他的都一样了。
中途退出并行循环
Parallel.For(0, 20000000, (i, state) =>
{
if (i == 1000)
{
state.Break();
return;
}
Console.Write(i + "\t");
});