我這裡針對現有的C#多線程技術進行一個匯總,一是復習,二是方便索引,文章部份知識點來源於網絡,非本人原創。
一、並行(異步):
1.System.Threading.Tasks命名空間下的(TPL):
1.1:Parallel.Invoke --並行執行多個任務,主線程等待並行執行完畢後才開始續續運行。
示例:
static void Main(string[] args)
{
Parallel.Invoke(new ParallelOptions() { MaxDegreeOfParallelism=2},Run1,Run2);
Console.WriteLine("我是主線程!");
Console.Read();
}
static void Run1()
{
Console.WriteLine("我是任務一,我運行3s");
Thread.Sleep(3000);
Console.WriteLine("任務一執先完成");
}
static void Run2()
{
Console.WriteLine("我是任務二,我運行5s");
Thread.Sleep(5000);
Console.WriteLine("任務二執先完成");
}
1.2:Parallel.For--循環迭代多個任務,多個任務之間存在並行情況,主線程等待循環迭代的多個任務執行完畢後才開始續續運行。
示例:
Parallel.For(0, 10, (i) => {
Console.WriteLine("我是第{0}個任務,線程ID是:{1}",i,Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(new Random().Next(10) * 10 * 500);
Console.WriteLine("線程ID是:{0}執行完成", Thread.CurrentThread.ManagedThreadId);
});
1.3:Parallel.ForEach--循環迭代多個任務,多個任務之間存在並行情況,主線程等待循環迭代的多個任務執行完畢後才開始續續運行。注意它有多個重載方法
示例:
var bag = new ConcurrentBag<int>();
Parallel.ForEach(Partitioner.Create(0, 100), i =>
{
for (int m = i.Item1; m < i.Item2; m++)
{
bag.Add(m);
Console.WriteLine("我是第{0}個任務,線程ID是:{1}", m, Thread.CurrentThread.ManagedThreadId);
}
});
Console.WriteLine("並行計算:集合有:{0}", bag.Count);
1.4:TAP(基於任務的異步編),使用Task類 (注意:默認任務開啟後,會在新線程中執行,主線程不會等待任務而是繼續下面的執行,若使用Task.WaitAll,則會等待相應的任務完成後才會執行)
示例:
//第一種方式啟動
var task1 = new Task(() => //實例化
{
Run1();
});
task1.Start(); //啟動
//第二種方式開啟
var task2 = Task.Factory.StartNew(() => //直接創建任務並啟動
{
Run2();
});
//主線程等待任務執行完
Task.WaitAll(task1, task2);
2.ParallelEnumerable類中的擴展方法(先將枚舉對象使用AsParallel轉換成ParallelQuery類型,然後就可以使用ParallelQuery在ParallelEnumerable類相關的擴展方法)
示例:
var resultList = testList.AsParallel().Where(i=>i>=100).ToList();
Console.WriteLine("resultList Count:{0}", resultList.Count);
3.創建新Thread--新線程啟動後,主線程與創建的線程各自執行,若需要主線程等待異步線程執行完成後才執行,則應使用asyncThread.Join方法。
示例:
static void AsyncThreadMethod()
{
Console.WriteLine("我是異步執行線程,線程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
}
static void AsyncThreadMethod(object state)
{
Console.WriteLine("我是異步執行線程,線程ID是:{0},狀態:{1}", Thread.CurrentThread.ManagedThreadId,state);
}
//創建線程並執行
Thread asyncThread = new Thread(new ThreadStart(AsyncThreadMethod));
asyncThread.IsBackground = true;
asyncThread.Start();
Thread asyncThread2 = new Thread(new ParameterizedThreadStart(AsyncThreadMethod));
asyncThread2.IsBackground = true;
asyncThread2.Start("這是來自主線程的參數");
4.使用ThreadPool.QueueUserWorkItem靜態方法--WaitCallback回調方法要求其必需帶一個object的參數
示例:
ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncThreadMethod));//不帶參數,則系統將state自動設為null ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncThreadMethod), "這是來自主線程的參數");
5.APM(異步編程模型),利用BeginInvoke與EndInvoke完成異步執行委托方法
示例:
Func<string, string> funcDelegate = (s) =>
{
Console.WriteLine("我是Func委托方法!");
return "委托方法參數:" + s;
};
//1.無阻塞異步回調
var aysncResult = funcDelegate.BeginInvoke("這是來自主線程的參數", new AsyncCallback((result) =>
{
//獲取委托對象,調用EndInvoke方法獲取運行結果
AsyncResult _result = (AsyncResult)result;
var func = (Func<string, string>)_result.AsyncDelegate;
string data = func.EndInvoke(_result);
Console.WriteLine(data +",附加參數:" + _result.AsyncState.ToString());
}),"其它參數");
//2.阻塞主線程,使主線程等待執行完畢
string data2 = null;
var aysncResult2 = funcDelegate.BeginInvoke("這是來自主線程的參數2", null, null);
data2 = funcDelegate.EndInvoke(aysncResult2);//第一種阻塞方法
while (!aysncResult2.IsCompleted) //第二種阻塞方法
{
Thread.Sleep(200); //虛擬操作
Console.WriteLine("主線程等待...");
}
data2 = funcDelegate.EndInvoke(aysncResult2);
WaitHandle[] waitHandles = new WaitHandle[]{ aysncResult2.AsyncWaitHandle };
while (WaitHandle.WaitAll(waitHandles, 5000)) //第三種阻塞方法
{
Console.WriteLine("主線程等待...");
}
6. EAP(基於事件的異步編程)--主要用在客戶端應用程序中
示例:
//例子一
var client = new WebClient();
client.DownloadProgressChanged += delegate(object s, DownloadProgressChangedEventArgs e)
{
Console.WriteLine("Download Percent:{0}", e.ProgressPercentage);
};
client.DownloadStringCompleted += delegate(object s,DownloadStringCompletedEventArgs e){
Console.WriteLine("Download Content Length:{0}",e.Result.Length);
Console.WriteLine("Download Completed!");
};
client.DownloadStringAsync(new Uri("http://www.zuowenjun.cn"));
//例子二
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (s, e) => {
Console.WriteLine("異步執行中。。。");
};
worker.RunWorkerCompleted += (s, e) => {
Console.WriteLine("異步執行完成。。。");
};
worker.RunWorkerAsync();
7.async和await關鍵字
示例:
public Task<double> GetValueAsync(double num1, double num2)
{
return Task.Run(() =>
{
for (int i = 0; i < 1000000; i++)
{
num1 = num1 / num2;
}
return num1;
});
}
public async void DisplayValue()
{
double result = await GetValueAsync(1234.5, 1.01);//此處會開新線程處理GetValueAsync任務,然後方法馬上返回
//這之後的所有代碼都會被封裝成委托,在GetValueAsync任務完成時調用
System.Diagnostics.Debug.WriteLine("Value is : " + result);
}
//調用
DisplayValue();//不會阻塞主線程
參考以下相關文章:
C#綜合揭秘——細說多線程(上)
C#綜合揭秘——細說多線程(下)
8天玩轉並行開發系列文章
.NET基礎拾遺(5)多線程開發基礎