C#多線程編程Task用法詳解
一、基本概念
Task優(yōu)勢(shì)
ThreadPool相比Thread來說具備了很多優(yōu)勢(shì),但是ThreadPool卻又存在一些使用上的不方便,例如:
- ThreadPool不支持線程的取消、完成、失敗通知等交互性操作;
- ThreadPool不支持線程執(zhí)行的先后次序;
.NET Framework 在4.0的時(shí)候提供了一個(gè)功能更強(qiáng)大的概念:Task。Task在ThreadPool的基礎(chǔ)上進(jìn)行了優(yōu)化,并提供了更多的API??聪旅嬉粋€(gè)簡(jiǎn)單的示例:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
// 創(chuàng)建Task
Task t = new Task(() =>
{
Console.WriteLine("任務(wù)開始工作.....");
Thread.Sleep(5000);
});
// 啟動(dòng)
t.Start();
t.ContinueWith((task) =>
{
Console.WriteLine("任務(wù)完成,完成時(shí)候的狀態(tài)為:");
Console.WriteLine("IsCanceled={0}\tIsCompleted={1}\tIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted);
});
Console.WriteLine("啟動(dòng)");
Console.ReadKey();
}
}
}二、Task用法
創(chuàng)建任務(wù)
Task創(chuàng)建的任務(wù)可以分為有返回值和無返回值兩種。
1、使用Task創(chuàng)建無返回值
先看一下Task的定義:

可以看到Task構(gòu)造函數(shù)的參數(shù)是Action委托。所以使用Task創(chuàng)建任務(wù)的代碼如下:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
Task task = new Task(() => TaskMethod("Task 1"));
Console.WriteLine("before start status:"+task.Status);
// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
task.Start();
Console.WriteLine("after start status:" + task.Status);
#endregion
Console.ReadKey();
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}程序運(yùn)行結(jié)果:

注:任務(wù)的狀態(tài),Start之前為Created,Start之后為WaitingToRun。
2、使用Task.Run方法創(chuàng)建任務(wù)
Task.Run創(chuàng)建的任務(wù)可以執(zhí)行啟動(dòng):
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
//Task task = new Task(() => TaskMethod("Task 1"));
//Console.WriteLine("before start status:"+task.Status);
//// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
//task.Start();
//Console.WriteLine("after start status:" + task.Status);
#endregion
#region 2、使用Task.Run創(chuàng)建任務(wù)
Task.Run(() => TaskMethod("Task Run"));
#endregion
Console.ReadKey();
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}程序運(yùn)行結(jié)果:

3、使用Factory方式創(chuàng)建任務(wù)
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
//Task task = new Task(() => TaskMethod("Task 1"));
//Console.WriteLine("before start status:"+task.Status);
//// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
//task.Start();
//Console.WriteLine("after start status:" + task.Status);
#endregion
#region 2、使用Task.Run創(chuàng)建任務(wù)
// Task.Run(() => TaskMethod("Task Run"));
#endregion
#region 3、使用Factory創(chuàng)建任務(wù)
// 使用Task.Factory創(chuàng)建
Task.Factory.StartNew(() => TaskMethod("Task 4"));
//標(biāo)記為長(zhǎng)時(shí)間運(yùn)行任務(wù),則任務(wù)不會(huì)使用線程池,而在單獨(dú)的線程中運(yùn)行。
Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
// 實(shí)例化TaskFactory對(duì)象,然后創(chuàng)建
TaskFactory factory = new TaskFactory();
factory.StartNew(() => TaskMethod("Task 6"));
#endregion
Console.ReadKey();
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
}
}程序運(yùn)行結(jié)果:

4、創(chuàng)建帶返回值的Task
代碼如下:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
//Task task = new Task(() => TaskMethod("Task 1"));
//Console.WriteLine("before start status:"+task.Status);
//// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
//task.Start();
//Console.WriteLine("after start status:" + task.Status);
#endregion
#region 2、使用Task.Run創(chuàng)建任務(wù)
// Task.Run(() => TaskMethod("Task Run"));
#endregion
#region 3、使用Task.Factory創(chuàng)建任務(wù)
//Task.Factory.StartNew(() => TaskMethod("Task 4"));
////標(biāo)記為長(zhǎng)時(shí)間運(yùn)行任務(wù),則任務(wù)不會(huì)使用線程池,而在單獨(dú)的線程中運(yùn)行。
//Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
#endregion
#region 4、創(chuàng)建帶返回值的任務(wù)
TaskMethodReturn("Main Thread Task");
// 創(chuàng)建帶返回值的Task
Task<int> task = CreateTask("Task 1");
// 啟動(dòng)
task.Start();
// 獲取返回值
int result1 = task.Result;
Console.WriteLine($"Task 1 Result is:{result1}");
Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
task2.Start();
int result2 = task2.Result;
Console.WriteLine($"Task 2 Result is:{result2}");
int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
Console.WriteLine($"Task 3 Result is:{result3}");
int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
Console.WriteLine($"Task 4 Result is:{result4}");
#endregion
Console.ReadKey();
}
/// <summary>
/// 返回一個(gè)Task<int>
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
static Task<int> CreateTask(string name)
{
// 參數(shù)是Func<int>
return new Task<int>(() => TaskMethodReturn(name));
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
static int TaskMethodReturn(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(2));
return 42;
}
}
}程序運(yùn)行結(jié)果:

我們?cè)谖恼麻_始的時(shí)候說過,Task是基于ThreadPool的,那么怎么證明呢?看下面的代碼:
/// <summary>
/// 測(cè)試Task的線程來自于ThreadPool
/// </summary>
static void Test()
{
// 設(shè)置線程池中最大的線程數(shù)
ThreadPool.SetMaxThreads(6, 6);
// 創(chuàng)建Task的集合
List<Task> taskList = new List<Task>();
// 創(chuàng)建int類型的集合,用于存放線程ID
List<int> threadIdList = new List<int>();
// 使用Task循環(huán)創(chuàng)建50個(gè)線程
for (int i = 0; i < 30; i++)
{
int k = i;
Task task = Task.Run(() =>
{
// 當(dāng)前線程ID加入到集合中
threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine($"this is {k} 循環(huán) ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// 休眠
Thread.Sleep(200);
});
// 把task加入到集合中
taskList.Add(task);
}
// 等待所有的線程執(zhí)行完
Task.WaitAll(taskList.ToArray());
// 輸出總數(shù)量
Console.WriteLine($"線程總數(shù):{threadIdList.Distinct().Count()}");
}程序運(yùn)行結(jié)果:

從結(jié)果中可以看出,Task中的線程確實(shí)是來自于ThreadPool。
三、常見方法
我們以下面的一個(gè)例子來講解Task中比較常見的幾個(gè)方法。多名開發(fā)者合作開發(fā)一個(gè)項(xiàng)目,每個(gè)人負(fù)責(zé)一個(gè)模塊的開發(fā),我們可以把這個(gè)過程認(rèn)為是多線程,代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
//Task task = new Task(() => TaskMethod("Task 1"));
//Console.WriteLine("before start status:"+task.Status);
//// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
//task.Start();
//Console.WriteLine("after start status:" + task.Status);
#endregion
#region 2、使用Task.Run創(chuàng)建任務(wù)
// Task.Run(() => TaskMethod("Task Run"));
#endregion
#region 3、使用Factory創(chuàng)建任務(wù)
// 使用Task.Factory創(chuàng)建
//Task.Factory.StartNew(() => TaskMethod("Task 4"));
////標(biāo)記為長(zhǎng)時(shí)間運(yùn)行任務(wù),則任務(wù)不會(huì)使用線程池,而在單獨(dú)的線程中運(yùn)行。
//Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
// 實(shí)例化TaskFactory對(duì)象,然后創(chuàng)建
//TaskFactory factory = new TaskFactory();
//factory.StartNew(() => TaskMethod("Task 6"));
#endregion
#region 4、創(chuàng)建帶返回值的任務(wù)
//TaskMethodReturn("Main Thread Task");
//// 創(chuàng)建帶返回值的Task
//Task<int> task = CreateTask("Task 1");
//// 啟動(dòng)
//task.Start();
//// 獲取返回值
//int result1 = task.Result;
//Console.WriteLine($"Task 1 Result is:{result1}");
//Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
//task2.Start();
//int result2 = task2.Result;
//Console.WriteLine($"Task 2 Result is:{result2}");
//int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
//Console.WriteLine($"Task 3 Result is:{result3}");
//int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
//Console.WriteLine($"Task 4 Result is:{result4}");
#endregion
#region 測(cè)試Task線程是來自于ThreadPool
// Test();
#endregion
// 合作開發(fā)項(xiàng)目,每個(gè)人負(fù)責(zé)一個(gè)模塊,可以認(rèn)為是多線程
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!"));
Task.Run(() => CodingShow("Kevin", "微信接口!"));
Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!"));
Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!"));
Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!"));
Console.ReadKey();
}
/// <summary>
/// 返回一個(gè)Task<int>
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
static Task<int> CreateTask(string name)
{
// 參數(shù)是Func<int>
return new Task<int>(() => TaskMethodReturn(name));
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
static int TaskMethodReturn(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(2));
return 42;
}
/// <summary>
/// 測(cè)試Task的線程來自于ThreadPool
/// </summary>
static void Test()
{
// 設(shè)置線程池中最大的線程數(shù)
ThreadPool.SetMaxThreads(6, 6);
// 創(chuàng)建Task的集合
List<Task> taskList = new List<Task>();
// 創(chuàng)建int類型的集合,用于存放線程ID
List<int> threadIdList = new List<int>();
// 使用Task循環(huán)創(chuàng)建50個(gè)線程
for (int i = 0; i < 30; i++)
{
int k = i;
Task task = Task.Run(() =>
{
// 當(dāng)前線程ID加入到集合中
threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine($"this is {k} 循環(huán) ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// 休眠
Thread.Sleep(200);
});
// 把task加入到集合中
taskList.Add(task);
}
// 等待所有的線程執(zhí)行完
Task.WaitAll(taskList.ToArray());
// 輸出總數(shù)量
Console.WriteLine($"線程總數(shù):{threadIdList.Distinct().Count()}");
}
/// <summary>
/// 模擬Coding過程
/// </summary>
/// <param name="name"></param>
/// <param name="projectName"></param>
static void CodingShow(string name, string projectName)
{
Console.WriteLine($"CodingShow Start {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
long lResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
lResult += i;
}
Console.WriteLine($"CodingShow End {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
}
}
}程序運(yùn)行結(jié)果:

這時(shí)需求發(fā)生了變化,所有的模塊都開發(fā)完成以后,開始搭建測(cè)試環(huán)境,修改代碼如下:
// 合作開發(fā)項(xiàng)目,每個(gè)人負(fù)責(zé)一個(gè)模塊,可以認(rèn)為是多線程
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!"));
Task.Run(() => CodingShow("Kevin", "微信接口!"));
Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!"));
Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!"));
Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!"));
Console.WriteLine("所有模塊都開發(fā)完成,開始搭建測(cè)試環(huán)境");程序運(yùn)行結(jié)果:

可以看到顯然不是我們想要的結(jié)果,模塊開發(fā)工作還沒有結(jié)束就搭建測(cè)試環(huán)境,即子線程還沒有結(jié)束,主線程就已經(jīng)結(jié)束了。要想實(shí)現(xiàn)我們想要的效果,那么必須使主線程等待所有子線程都結(jié)束以后,主線程才能結(jié)束。
1、WaitAll()
WaitAll()表示等待所有的Task都執(zhí)行完成。看WaitAll()的定義:

WaitAll()方法有很多重載,我們?cè)谶@里使用第一個(gè)重載方法,即參數(shù)是Task[]數(shù)組。查看Run()方法的定義時(shí),我們會(huì)發(fā)現(xiàn)Run()方法的返回值就是Task類型,我們使用WaitAll()修改上面的代碼:
// 定義一個(gè)Task類型的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
// 等待所有模塊都開發(fā)完成,才能搭建測(cè)試環(huán)境
Task.WaitAll(taskList.ToArray());
Console.WriteLine("所有模塊都開發(fā)完成,開始搭建測(cè)試環(huán)境");程序運(yùn)行結(jié)果:

WaitAll()會(huì)使程序產(chǎn)生卡頓。
加載首頁信息的時(shí)候可以使用WaitAll()方法。一個(gè)首頁信息可能來自于幾部分的數(shù)據(jù),每一部分的數(shù)據(jù)對(duì)應(yīng)一個(gè)線程,只有所有的線程都執(zhí)行完畢才顯示首頁信息。
2、WaitAny()
這時(shí)需求又發(fā)生改變了:某一個(gè)模塊開發(fā)完成以后就搭建測(cè)試環(huán)境。這時(shí)候就可以使用WaitAny()了。WaitAny()表示等待其中任何一個(gè)任務(wù)完成就會(huì)進(jìn)入下一個(gè)任務(wù),定義如下:

修改后的代碼如下:
// 定義一個(gè)Task類型的集合
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
// 等待所有模塊都開發(fā)完成,才能搭建測(cè)試環(huán)境
Task.WaitAny(taskList.ToArray());
Console.WriteLine("有模塊開發(fā)完成,開始搭建測(cè)試環(huán)境");程序運(yùn)行結(jié)果:

可以看到:設(shè)計(jì)數(shù)據(jù)庫模塊完成以后,就開始搭建測(cè)試環(huán)境了。如何需求。
WaitAny()會(huì)使程序產(chǎn)生卡頓。
有一個(gè)列表數(shù)據(jù),數(shù)據(jù)可以來源于接口、緩存、數(shù)據(jù)庫等,可以開啟多個(gè)線程,只要有一個(gè)線程執(zhí)行完畢就可以繼續(xù)執(zhí)行下面的步驟,這時(shí)就可以使用WaitAny()。
3、ContinueWhenAll()
WaitAll()會(huì)卡頓界面,那么有沒有不卡頓界面的呢?ContinueWhenAll和WaitAll實(shí)現(xiàn)的效果一樣,代碼如下:
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模塊開發(fā)完成"));程序運(yùn)行結(jié)果:

4、ContinueWhenAny
ContinueWhenAny實(shí)現(xiàn)的效果和WaitAny一樣,ContinueWhenAny不會(huì)卡頓界面,代碼如下:
List<Task> taskList = new List<Task>();
Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
TaskFactory factory = new TaskFactory();
factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一個(gè)模塊開發(fā)完成"));程序運(yùn)行結(jié)果:

ContinueWhenAll()和ContinueWhenAny()都會(huì)開啟一個(gè)新的線程。
5、ContinueWith
ContinueWith表示回調(diào),代碼如下:
Task.Run(() => { Console.WriteLine("任務(wù)執(zhí)行完成"); }).ContinueWith(p=>
{
Task.Run(() => { Console.WriteLine("執(zhí)行回調(diào)"); });
});程序執(zhí)行結(jié)果:

程序完整代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace TaskDemo
{
class Program
{
static void Main(string[] args)
{
#region 1、使用Task創(chuàng)建任務(wù)
//Task task = new Task(() => TaskMethod("Task 1"));
//Console.WriteLine("before start status:"+task.Status);
//// Task創(chuàng)建的任務(wù)必須調(diào)用start方法才能啟動(dòng)
//task.Start();
//Console.WriteLine("after start status:" + task.Status);
#endregion
#region 2、使用Task.Run創(chuàng)建任務(wù)
// Task.Run(() => TaskMethod("Task Run"));
#endregion
#region 3、使用Factory創(chuàng)建任務(wù)
// 使用Task.Factory創(chuàng)建
//Task.Factory.StartNew(() => TaskMethod("Task 4"));
////標(biāo)記為長(zhǎng)時(shí)間運(yùn)行任務(wù),則任務(wù)不會(huì)使用線程池,而在單獨(dú)的線程中運(yùn)行。
//Task.Factory.StartNew(() => TaskMethod("Task 5"), TaskCreationOptions.LongRunning);
// 實(shí)例化TaskFactory對(duì)象,然后創(chuàng)建
//TaskFactory factory = new TaskFactory();
//factory.StartNew(() => TaskMethod("Task 6"));
#endregion
#region 4、創(chuàng)建帶返回值的任務(wù)
//TaskMethodReturn("Main Thread Task");
//// 創(chuàng)建帶返回值的Task
//Task<int> task = CreateTask("Task 1");
//// 啟動(dòng)
//task.Start();
//// 獲取返回值
//int result1 = task.Result;
//Console.WriteLine($"Task 1 Result is:{result1}");
//Task<int> task2 = new Task<int>(() => TaskMethodReturn("Task 2"));
//task2.Start();
//int result2 = task2.Result;
//Console.WriteLine($"Task 2 Result is:{result2}");
//int result3= Task.Run<int>(() => TaskMethodReturn("Task 3")).Result;
//Console.WriteLine($"Task 3 Result is:{result3}");
//int result4 = Task.Factory.StartNew<int>(() => TaskMethodReturn("Task 4")).Result;
//Console.WriteLine($"Task 4 Result is:{result4}");
#endregion
#region 測(cè)試Task線程是來自于ThreadPool
// Test();
#endregion
// 合作開發(fā)項(xiàng)目,每個(gè)人負(fù)責(zé)一個(gè)模塊,可以認(rèn)為是多線程
// 無序
//Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
//Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!"));
//Task.Run(() => CodingShow("Kevin", "微信接口!"));
//Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!"));
//Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!"));
//Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!"));
//Console.WriteLine("所有模塊都開發(fā)完成,開始搭建測(cè)試環(huán)境");
#region WaitAll
//// 定義一個(gè)Task類型的集合
//List<Task> taskList = new List<Task>();
//Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
//taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
//taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
//taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
//taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
//taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
//// 等待所有模塊都開發(fā)完成,才能搭建測(cè)試環(huán)境
//Task.WaitAll(taskList.ToArray());
//Console.WriteLine("所有模塊都開發(fā)完成,開始搭建測(cè)試環(huán)境");
#endregion
#region WaitAny
// 定義一個(gè)Task類型的集合
//List<Task> taskList = new List<Task>();
//Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
//taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
//taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
//taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
//taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
//taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
//// 等待所有模塊都開發(fā)完成,才能搭建測(cè)試環(huán)境
//Task.WaitAny(taskList.ToArray());
//Console.WriteLine("有模塊開發(fā)完成,開始搭建測(cè)試環(huán)境");
#endregion
#region ContinueWhenAll
//List<Task> taskList = new List<Task>();
//Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
//taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
//taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
//taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
//taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
//taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
//TaskFactory factory = new TaskFactory();
//factory.ContinueWhenAll(taskList.ToArray(), t => Console.WriteLine("所有模塊開發(fā)完成"));
#endregion
#region ContinueWhenAll
//List<Task> taskList = new List<Task>();
//Console.WriteLine("開始合作開發(fā)一個(gè)大項(xiàng)目!");
//taskList.Add(Task.Run(() => CodingShow("Tom", "搭建微服務(wù)架構(gòu)!")));
//taskList.Add(Task.Run(() => CodingShow("Kevin", "微信接口!")));
//taskList.Add(Task.Run(() => CodingShow("Jack", "搭建后臺(tái)框架!")));
//taskList.Add(Task.Run(() => CodingShow("Alex", "設(shè)計(jì)數(shù)據(jù)庫!")));
//taskList.Add(Task.Run(() => CodingShow("Lee", "支付寶接口對(duì)接!")));
//TaskFactory factory = new TaskFactory();
//factory.ContinueWhenAny(taskList.ToArray(), t => Console.WriteLine("某一個(gè)模塊開發(fā)完成"));
#endregion
#region ContinueWith
Task.Run(() => { Console.WriteLine("任務(wù)執(zhí)行完成"); }).ContinueWith(p=>
{
Task.Run(() => { Console.WriteLine("執(zhí)行回調(diào)"); });
});
#endregion
Console.ReadKey();
}
/// <summary>
/// 返回一個(gè)Task<int>
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
static Task<int> CreateTask(string name)
{
// 參數(shù)是Func<int>
return new Task<int>(() => TaskMethodReturn(name));
}
static void TaskMethod(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
static int TaskMethodReturn(string name)
{
Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(TimeSpan.FromSeconds(2));
return 42;
}
/// <summary>
/// 測(cè)試Task的線程來自于ThreadPool
/// </summary>
static void Test()
{
// 設(shè)置線程池中最大的線程數(shù)
ThreadPool.SetMaxThreads(6, 6);
// 創(chuàng)建Task的集合
List<Task> taskList = new List<Task>();
// 創(chuàng)建int類型的集合,用于存放線程ID
List<int> threadIdList = new List<int>();
// 使用Task循環(huán)創(chuàng)建50個(gè)線程
for (int i = 0; i < 30; i++)
{
int k = i;
Task task = Task.Run(() =>
{
// 當(dāng)前線程ID加入到集合中
threadIdList.Add(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine($"this is {k} 循環(huán) ThreadID:{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
// 休眠
Thread.Sleep(200);
});
// 把task加入到集合中
taskList.Add(task);
}
// 等待所有的線程執(zhí)行完
Task.WaitAll(taskList.ToArray());
// 輸出總數(shù)量
Console.WriteLine($"線程總數(shù):{threadIdList.Distinct().Count()}");
}
/// <summary>
/// 模擬Coding過程
/// </summary>
/// <param name="name"></param>
/// <param name="projectName"></param>
static void CodingShow(string name, string projectName)
{
Console.WriteLine($"CodingShow Start {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
long lResult = 0;
for (int i = 0; i < 1_000_000_000; i++)
{
lResult += i;
}
Console.WriteLine($"CodingShow End {name} {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")} ");
}
}
}到此這篇關(guān)于C#多線程編程Task用法的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#如何將Access中以時(shí)間段條件查詢的數(shù)據(jù)添加到ListView中
這篇文章主要介紹了C# 將Access中以時(shí)間段條件查詢的數(shù)據(jù)添加到ListView中,需要的朋友可以參考下2017-07-07
C#實(shí)現(xiàn)讀取和設(shè)置文件與文件夾的權(quán)限
這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)讀取和設(shè)置文件與文件夾的權(quán)限,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
詳解c# 強(qiáng)制轉(zhuǎn)換和類型轉(zhuǎn)換
這篇文章主要介紹了c# 強(qiáng)制轉(zhuǎn)換和類型轉(zhuǎn)換的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下2020-10-10
jQuery結(jié)合C#實(shí)現(xiàn)上傳文件的方法
這篇文章主要介紹了jQuery結(jié)合C#實(shí)現(xiàn)上傳文件的方法,涉及C#文件上傳的相關(guān)技巧,需要的朋友可以參考下2015-04-04
C# httpwebrequest訪問HTTPS錯(cuò)誤處理方法
下面小編就為大家?guī)硪黄狢# httpwebrequest訪問HTTPS錯(cuò)誤處理方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01

