Parallel.For/ForEach是數據層面的并行,本文所講的Task是將不同的操作并行執行,本文主要內容:
.Net中Task的工作模式是Fork/Join或者Master/Worker模式。核心思想是Master負責接受Client的請求,并且負責將請求分配給最終的Wroker,Worker執行完自己的工作后分別返回給Master。由Master匯總最終的結果并且返回給Client。
在.Net的Task并行編程中。一個Worker代表一個Task。
Parallel.Invoke是最簡單的辦法Task并行編程模式。
該方法會創建一個Task用于執行作為參數的方法。
class TaskDemo { public void Action1() { Console.WriteLine("in action1"); } public void Action2() { Console.WriteLine("in action2"); } public void StartTasks() { var task1 = Task.Factory.StartNew(Action1); var task2 = Task.Factory.StartNew(Action2); Task.WaitAll(task1, task2); } }
以上代碼使用TaskFactory.StartNew方法創建了兩個Task。task1用于執行Action1,task2用于執行Action2.
StartNew只是創建了一個task,并將該task加入到一個工作隊列(work queue),當時該Task并沒有馬上執行,task什么時候執行是由TaskScheduler決定。TaskScheduler會將需要執行的task從中拿出來,然后才開始執行。(以上代碼使用的是默認TaskScheduler)
TaskScheduler很可能馬上執行,也有可能在未來的某一個特定時間點進行執行,取決于調度算法,以及CPU資源等。
剛開始說了。Task編程使用的是Master/Worker模式,該模式中最后一點是Worker最終會將結果返回給Master。由Master統一將結果進行匯總。在Task編程中有兩個方法:
上面2.2的代碼中已經使用了WaitAll,該方法將會等待兩個Action完成之后才會進行返回,將上面的方法做一點改變。
class TaskDemo { public void Action1() { Thread.Sleep(1000); Console.WriteLine("in action1"); } public void Action2() { Thread.Sleep(3000); Console.WriteLine("in action2"); } public void StartTasks() { var task1 = Task.Factory.StartNew(Action1); var task2 = Task.Factory.StartNew(Action2); Task.WaitAll(task1, task2); Console.WriteLine("Finished"); } }
WaitAll之后再打印出”Finished“,按照WaitAll的定義,Finished永遠是最后打印出來的字符串。
將上面代碼的WaitAll修改成WaitAny
public void StartTasks() { var task1 = Task.Factory.StartNew(Action1); var task2 = Task.Factory.StartNew(Action2); Task.WaitAny(task1, task2); Console.WriteLine("Finished"); }
最終運行結果:
可以看出使用了WaitAny后,沒有等待Task2執行完畢,程序就回到了主線程,先打印出了Finished。
Task取消使用一個叫做coorperative cancellation的模型進行Task取消。主要使用CancellationTokenSource完成。該對象有一個CancellactionToken。當StartNew一個Task時候,可以將toker傳給被創建的task。當CancellationTokenSource調用Cancel后,Task對應的Token狀態將會變為取消(Canceled),Task的狀態也會變為取消。這時候如果Task還沒有啟動,Task將不會再執行任務。
當然最后在每個Task內部也對Token進行判斷,如果token已經取消,則不再執行當前Action(有些task可能在CancellactionToke被取消之前已經啟動了),修改一下執行圖:
class TaskDemo { public void Action1(CancellationTokenSource cts) { if(cts.IsCancellationRequested) { return; } Console.WriteLine("in action1"); } public void Action2(CancellationTokenSource cts) { Thread.Sleep(2000); if (cts.IsCancellationRequested) { Console.WriteLine("action2 is canceled"); return; } Console.WriteLine("in action2"); } public void StartTasks() { CancellationTokenSource cts = new CancellationTokenSource(); var task1 = Task.Factory.StartNew(() => Action1(cts), cts.Token); var task2 = Task.Factory.StartNew(() => Action2(cts), cts.Token); Task.WaitAny(task1, task2); cts.Cancel(); Console.WriteLine("Finished"); } }
上面的運行結果有可能“action2 is canceled"這句話不會打印出來,因為有可能在Task2執行之前cts已經取消了。會進入流程圖中第一個If判斷點==》Not will run task
新聞熱點
疑難解答