菜鸟学习C#并行编程.docx

上传人:b****6 文档编号:7074237 上传时间:2023-01-17 格式:DOCX 页数:18 大小:1.63MB
下载 相关 举报
菜鸟学习C#并行编程.docx_第1页
第1页 / 共18页
菜鸟学习C#并行编程.docx_第2页
第2页 / 共18页
菜鸟学习C#并行编程.docx_第3页
第3页 / 共18页
菜鸟学习C#并行编程.docx_第4页
第4页 / 共18页
菜鸟学习C#并行编程.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

菜鸟学习C#并行编程.docx

《菜鸟学习C#并行编程.docx》由会员分享,可在线阅读,更多相关《菜鸟学习C#并行编程.docx(18页珍藏版)》请在冰豆网上搜索。

菜鸟学习C#并行编程.docx

菜鸟学习C#并行编程

C#并行编程-Task-菜鸟学习并行编程

菜鸟学习并行编程,参考《C#并行编程高级教程.PDF》,如有错误,欢迎指正。

任务简介

TPL引入新的基于任务的编程模型,通过这种编程模型可以发挥多核的功效,提升应用程序的性能,不需要编写底层复杂且重量级的线程代码。

但需要注意:

任务并不是线程(任务运行的时候需要使用线程,但并不是说任务取代了线程,任务代码是使用底层的线程(软件线程,调度在特定的硬件线程或逻辑内核上)运行的,任务与线程之间并没有一对一的关系。

创建一个新的任务时,调度器(调度器依赖于底层的线程池引擎)会使用工作窃取队列找到一个最合适的线程,然后将任务加入队列,任务所包含的代码会在一个线程中运行。

如图:

System.Threading.Tasks.Task

一个Task表示一个异步操作,Task提供了很多方法和属性,通过这些方法和属性能够对Task的执行进行控制,并且能够获得其状态信息。

Task的创建和执行都是独立的,因此可以对关联操作的执行拥有完全的控制权。

使用Parallel.For、Parallel.ForEach的循环迭代的并行执行,TPL会在后台创建System.Threading.Tasks.Task的实例。

使用Parallel.Invoke时,TPL也会创建与调用的委托数目一致的System.Threading.Tasks.Task的实例。

注意项

程序中添加很多异步的操作作为Task实例加载的时候,为了充分利用运行时所有可用的逻辑内核,任务调度器会尝试的并行的运行这些任务,也会尝试在所有的可用内核上对工作进行负载均衡。

但在实际的编码过程当中,并不是所有的代码片段都能够方便的用任务来运行,因为任务会带来额外的开销,尽管这种开销比添加线程所带来的开销要小,但是仍然需要将这个开销考虑在内。

Task状态与生命周期

一个Task实例只会完成其生命周期一次,当Task到达它的3种肯呢过的最终状态之一是,就无法回到之前的任何状态

下面贴代码,详解见注释,方便大家理解Task的状态:

classProgram

{

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

/*创建一个任务不调用不执行状态为Created*/

Tasktk=newTask(()=>

{

});

Console.WriteLine(tk.Status.ToString());

/*创建一个任务执行状态为WaitingToRun*/

Tasktk1=newTask(()=>

{

});

tk1.Start();/*对于安排好的任务,就算调用Start方法也不会立马启动此时任务的状态为WaitingToRun*/

Console.WriteLine(tk1.Status.ToString());

/*创建一个主任务*/

TaskmainTask=newTask(()=>

{

SpinWait.SpinUntil(()=>

{

returnfalse;

},30000);

});

/*将子任务加入到主任务完成之后执行*/

TasksubTask=mainTask.ContinueWith((t1)=>

{

});

/*启动主任务*/

mainTask.Start();

/*此时子任务状态为WaitingForActivation*/

Console.WriteLine(subTask.Status.ToString());

 

/*创建一个任务执行后等待一段时间并行未结束的情况下状态为Running*/

Tasktk2=newTask(()=>

{

SpinWait.SpinUntil(()=>false,30000);

});

tk2.Start();/*对于安排好的任务,就算调用Start方法也不会立马启动*/

SpinWait.SpinUntil(()=>false,300);

Console.WriteLine(tk2.Status.ToString());

 

/*创建一个任务然后取消该任务状态为Canceled*/

CancellationTokenSourcects=newCancellationTokenSource();

Tasktk3=newTask(()=>

{

for(inti=0;i

{

if(!

cts.Token.IsCancellationRequested)

{

cts.Token.ThrowIfCancellationRequested();

}

}

},cts.Token);

tk3.Start();/*启动任务*/

SpinWait.SpinUntil(()=>false,100);

cts.Cancel();/*取消该任务执行但并非立马取消所以对于Canceled状态也不会立马生效*/

SpinWait.SpinUntil(()=>false,1000);

Console.WriteLine(tk3.Status.ToString()+""+tk3.IsCanceled);

SpinWait.SpinUntil(()=>false,1000);

Console.WriteLine(tk3.Status.ToString()+""+tk3.IsCanceled);

SpinWait.SpinUntil(()=>false,1000);

Console.WriteLine(tk3.Status.ToString()+""+tk3.IsCanceled);

/*创建一个任务让它成功的运行完成会得到RanToCompletion状态*/

Tasktk4=newTask(()=>

{

SpinWait.SpinUntil(()=>false,10);

});

tk4.Start();

SpinWait.SpinUntil(()=>false,300);

Console.WriteLine(tk4.Status.ToString());

/*创建一个任务让它运行失败会得到Faulted状态*/

Tasktk5=newTask(()=>

{

thrownewException();

});

tk5.Start();

SpinWait.SpinUntil(()=>false,300);

Console.WriteLine(tk5.Status.ToString());

Console.ReadLine();

}

}

classProduct

{

publicstringName{get;set;}

publicstringCategory{get;set;}

publicintSellPrice{get;set;}

}

使用任务来对代码进行并行化

使用Parallel.Invoke可以并行加载多个方法,使用Task实例也能完成同样的工作,下面贴代码:

classProgram

{

privatestaticConcurrentQueuequeue=null;

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

queue=newConcurrentQueue();

Tasktk1=newTask(()=>{SetProduct

(1);SetProduct(3);});

Tasktk2=newTask(()=>SetProduct

(2));

tk1.Start();

tk2.Start();

Console.ReadLine();

}

staticvoidSetProduct(intindex)

{

Parallel.For(0,10000,(i)=>

{

Productmodel=newProduct();

model.Name="Name"+i;

model.SellPrice=i;

model.Category="Category"+i;

queue.Enqueue(model);

});

Console.WriteLine("SetProduct{0}执行完成",index);

}

}

classProduct

{

publicstringName{get;set;}

publicstringCategory{get;set;}

publicintSellPrice{get;set;}

}

等待任务完成Task.WaitAll

Task.WaitAll方法,这个方法是同步执行的,在Task作为参数被接受,所有Task结束其执行前,主线程不会继续执行下一条指令,下面贴代码

classProgram

{

privatestaticConcurrentQueuequeue=null;

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

queue=newConcurrentQueue();

Tasktk1=newTask(()=>{SetProduct

(1);SetProduct(3);});

Tasktk2=newTask(()=>SetProduct

(2));

tk1.Start();

tk2.Start();

/*等待任务执行完成后再输出======*/

Task.WaitAll(tk1,tk2);

Console.WriteLine("等待任务执行完成后再输出======");

Tasktk3=newTask(()=>{SetProduct

(1);SetProduct(3);});

Tasktk4=newTask(()=>SetProduct

(2));

tk3.Start();

tk4.Start();

/*等待任务执行前输出======*/

Console.WriteLine("等待任务执行前输出======");

Task.WaitAll(tk3,tk4);

 

Console.ReadLine();

}

staticvoidSetProduct(intindex)

{

Parallel.For(0,10000,(i)=>

{

Productmodel=newProduct();

model.Name="Name"+i;

model.SellPrice=i;

model.Category="Category"+i;

queue.Enqueue(model);

});

Console.WriteLine("SetProduct{0}执行完成",index);

}

}

Task.WaitAll限定等待时长

queue=newConcurrentQueue();

Tasktk1=newTask(()=>{SetProduct

(1);SetProduct(3);});

Tasktk2=newTask(()=>SetProduct

(2));

tk1.Start();

tk2.Start();

/*如果tk1tk2没能在10毫秒内完成则输出******/

if(!

Task.WaitAll(newTask[]{tk1,tk2},10))

{

Console.WriteLine("******");

}

Console.ReadLine();

如图10毫秒没有完成任务,则输出了****

通过取消标记取消任务

通过取消标记来中断Task实例的执行。

CancellationTokenSource,CancellationToken下的IsCanceled属性标志当前是否已经被取消,取消任务,任务也不一定会马上取消,下面贴代码:

classProgram

{

privatestaticConcurrentQueuequeue=null;

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

queue=newConcurrentQueue();

System.Threading.CancellationTokenSourcetoken=newCancellationTokenSource();

Tasktk1=Task.Factory.StartNew(()=>SetProduct(token.Token));

Tasktk2=Task.Factory.StartNew(()=>SetProduct(token.Token));

Thread.Sleep(10);

/*取消任务操作*/

token.Cancel();

try

{

/*等待完成*/

Task.WaitAll(newTask[]{tk1,tk2});

}

catch(AggregateExceptionex)

{

/*如果当前的任务正在被取消,那么还会抛出一个TaskCanceledException异常,这个异常包含在AggregateException异常中*/

Console.WriteLine("tk1Canceled:

{0}",tk1.IsCanceled);

Console.WriteLine("tk1Canceled:

{0}",tk2.IsCanceled);

}

Thread.Sleep(2000);

Console.WriteLine("tk1Canceled:

{0}",tk1.IsCanceled);

Console.WriteLine("tk1Canceled:

{0}",tk2.IsCanceled);

Console.ReadLine();

}

staticvoidSetProduct(System.Threading.CancellationTokenct)

{

/*每一次循环迭代,都会有新的代码调用ThrowIfCancellationRequested

*这行代码能够对OpreationCanceledException异常进行观察

*并且这个异常的标记与Task实例关联的那个标记进行比较,如果两者相同,而且IsCancelled属性为True,那么Task实例就知道存在一个要求取消的请求,并且会将状态转变为Canceled状态,中断任务执行。

*如果当前的任务正在被取消,那么还会抛出一个TaskCanceledException异常,这个异常包含在AggregateException异常中

/*检查取消标记*/

ct.ThrowIfCancellationRequested();

for(inti=0;i<50000;i++)

{

Productmodel=newProduct();

model.Name="Name"+i;

model.SellPrice=i;

model.Category="Category"+i;

queue.Enqueue(model);

ct.ThrowIfCancellationRequested();

}

Console.WriteLine("SetProduct执行完成");

}

}

classProduct

{

publicstringName{get;set;}

publicstringCategory{get;set;}

publicintSellPrice{get;set;}

}

Task异常处理当很多任务并行运行的时候,可能会并行发生很多异常。

Task实例能够处理一组一组的异常,这些异常有System.AggregateException类处理

classProgram

{

privatestaticConcurrentQueuequeue=null;

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

queue=newConcurrentQueue();

System.Threading.CancellationTokenSourcetoken=newCancellationTokenSource();

Tasktk1=Task.Factory.StartNew(()=>SetProduct(token.Token));

Thread.Sleep(2000);

if(tk1.IsFaulted)

{

/*循环输出异常*/

foreach(Exceptionexintk1.Exception.InnerExceptions)

{

Console.WriteLine("tk1Exception:

{0}",ex.Message);

}

}

Console.ReadLine();

}

staticvoidSetProduct(System.Threading.CancellationTokenct)

{

for(inti=0;i<5;i++)

{

thrownewException(string.Format("ExceptionIndex{0}",i));

}

Console.WriteLine("SetProduct执行完成");

}

}

Task返回值Task

classProgram

{

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

Task>tk1=Task>.Factory.StartNew(()=>SetProduct());

Task.WaitAll(tk1);

Console.WriteLine(tk1.Result.Count);

Console.WriteLine(tk1.Result[0].Name);

Console.ReadLine();

}

staticListSetProduct()

{

Listresult=newList();

for(inti=0;i<500;i++)

{

Productmodel=newProduct();

model.Name="Name"+i;

model.SellPrice=i;

model.Category="Category"+i;

result.Add(model);

}

Console.WriteLine("SetProduct执行完成");

returnresult;

}

}

通过延续串联多个任务

ContinueWith:

创建一个目标Task完成时,异步执行的延续程序,await,如代码所示:

classProgram

{

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

/*创建任务t1*/

Taskt1=Task.Factory.StartNew(()=>

{

Console.WriteLine("执行t1任务");

SpinWait.SpinUntil(()=>

{

returnfalse;

},2000);

});

/*创建任务t2t2任务的执行依赖与t1任务的执行完成*/

Taskt2=t1.ContinueWith((t)=>

{

Console.WriteLine("执行t2任务");

SpinWait.SpinUntil(()=>

{

returnfalse;

},2000);

});

/*创建任务t3t3任务的执行依赖与t2任务的执行完成*/

Taskt3=t2.ContinueWith((t)=>

{

Console.WriteLine("执行t3任务");

});

Console.ReadLine();

}

}

TaskContinuationOptions

TaskContinuationOptions参数,可以控制延续另一个任的任务调度和执行的可选行为。

下面看代码:

classProgram

{

/*coder:

释迦苦僧*/

staticvoidMain(string[]args)

{

/*创建任务t1*/

Taskt1=Task.Factory.StartNew(()=>

{

Console.WriteLine("执行t1任务");

SpinWait.SpinUntil(()=>

{

returnfalse;

},2000);

thrownewException("异常");

});

/*创建任务t2t2任务的执行依赖与t1任务的执行完成*/

Taskt2=t1.ContinueWith((t)=>

{

Console.WriteLine(t.Status);

Console.WriteLine("执行t2任务");

SpinWait.SpinUntil(()=>

{

returnfalse;

},2000);

/*定义TaskContinuationOpt

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 幼儿读物

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1