昨天在部門分享.net多線程的一些內容,特此在博客記錄下。內容如下:
進程與線程
1.什么是進程
進程是指在系統中正在運行的一個應用程序
每個進程之間是獨立的,每個進程均運行在其專用且受保護的內存空間內
2.什么是線程
1個進程要想執行任務,必須得有線程(每1個進程至少要有1條線程)
線程是進程的基本執行單元,一個進程(程序)的所有任務都在線程中執行
3.線程的串行
1個線程中任務的執行是串行的
如果要在1個線程中執行多個任務,那么只能一個一個地按順序執行這些任務
也就是說,在同一時間內,1個線程只能執行1個任務
4.什么是多線程
1個進程中可以開啟多條線程,每條線程可以並行(同時)執行不同的任務
並發與並行
並發(concurrency):
在同一時刻只能有一條指令執行,
多個線程程指令被快速的輪換執行
並行(parallel):
在同一時刻,有多條指令
在多個處理器上同時執行。
ps:(上面中的兩個小圖,來自網上,如有侵權,請聯系本人刪除)
多線程的原理與優缺點
同一時間,單CPU只能處理1條線程,只有1條線程在工作(執行)多線程並發(同時)執行,
其實是CPU快速地在多條線程之間調度(切換)如果CPU調度線程的時間足夠快,就造成了多線程並行執行的假象
優點
1、能適當提高程序的執行效率
2、能適當提高資源利用率(CPU、內存、帶寬)
缺點
1、開啟線程需要占用一定的內存空間
(默認情況下,主線程占用1M,子線程占用512KB)
2、CPU在調度線程上的開銷就越大(上下文切換)
3、並發線程數過高可能出現大量的IO阻塞
如果串行算法可以在不到1S內就能得出結果,那么切換到並行的加速效果不明顯
目前沒有很好的判斷標准,最好的方式就是不停的測試
線程上下文切換,CPU暫停程序執行,將當前寄存器的值保存到內存中,從現有線程中選出一個線程加載上下文結構到寄存器,再開始執行。
Windows大約每30ms執行一次垃圾回收,CLR會暫停所有的線程,遍歷所有的對象進行垃圾清除。
線程安全的集合
System.Collections.Concurrent命名空間下的類型來用於並行循環體內。
類 |
說明 |
BlockingCollection<T> |
為實現 IProducerConsumerCollection<T> 的線程安全 集合提供阻止和限制功能。 |
ConcurrentBag<T> |
表示對象的線程安全的無序集合。 |
ConcurrentDictionary<TKey, TValue> |
表示可由多個線程同時訪問的鍵值對的線程安全集合。 |
ConcurrentQueue<T> |
表示線程安全的先進先出 (FIFO) 集合。 |
ConcurrentStack<T> |
表示線程安全的后進先出 (LIFO) 集合。 |
OrderablePartitioner<TSource> |
表示將一個可排序數據源拆分成多個分區的特定方式。 |
Partitioner |
提供針對數組、列表和可枚舉項的常見分區策略。 |
Partitioner<TSource> |
表示將一個數據源拆分成多個分區的特定方式。 |
線程狀態
成員名稱 |
說明 |
Aborted |
線程處於 Stopped 狀態中。 |
AbortRequested |
已對線程調用了 Thread.Abort 方法,但線程尚未收到試圖終止它的掛起的System.Threading.ThreadAbortException。 |
Background |
線程正作為后台線程執行(相對於前台線程而言)。此狀態可以通過設置Thread.IsBackground 屬性來控制。 |
Running |
線程已啟動,它未被阻塞,並且沒有掛起的 ThreadAbortException。 |
Stopped |
線程已停止。 |
StopRequested |
正在請求線程停止。這僅用於內部。 |
Suspended |
線程已掛起。 |
SuspendRequested |
正在請求線程掛起。 |
Unstarted |
尚未對線程調用 Thread.Start 方法。 |
WaitSleepJoin |
由於調用 Wait、Sleep 或 Join,線程已被阻止。 |
C#多線程環境下調用 HttpWebRequest 並發連接限制
.net 的 HttpWebRequest 或者 WebClient 在多線程情況下存在並發連接限制,這個限制在桌面操作系統windows 7 下默認是2,在服務器操作系統上默認為10。不修改這個並發連接限制,客戶端同時可以建立的 http 連接數就只有2個或10個。
經過驗證,在.net core下也是如此。
.net cor中源碼地址:https://github.com/dotnet/corefx/blob/master/src/System.Net.Requests/src/System/Net/HttpWebRequest.cs
對應的.net freamwork中的代碼:
之所以有這個並發連接限制,是因為 http 1.0 和 http 1.1 標准規定並發連接數最大為2.。不過目前主流的瀏覽器都已經不遵循這個規則了,但 .net 依然默認遵循這個規則。
對於.net core,這個設置系統級別的,不過沒讀注冊表。。。對了,linux沒注冊表。當應該讀系統的環境變量才行的。(作者未驗證,歡迎驗證過的同學評論)
解決辦法:
System.Net.ServicePointManager.DefaultConnectionLimit = 512; //第一種 //HttpWebRequest.ServicePoint.ConnectionLimit=512; //第二種
.net freawork 下,也可以在配置文件app.config中設置:
<system.net> <defaultProxy enabled="false"> <proxy/> <bypasslist/> <module/> </defaultProxy> <connectionManagement> <add address="*" maxconnection="10"/> </connectionManagement> </system.net>
另外提一點:HttpWebRequest默認會使用IE代理設置,上面的配置文件設置不啟用代理。
還有一種方法 httpWebRequest.Proxy = null;
這樣可以減少.net使用代理所需要花費的時間和占用的資源。
Demo
針對上述理論,我寫了Thread 、 Task 、Parallel 的各種demo ,以及多線程的取消的Demo。由於篇幅有限,就在此不做展示,源代碼地址:
https://github.com/li-shaoke/ThreadDemo
參考自:
https://www.cnblogs.com/summer_adai/archive/2013/04/26/3045274.html
https://www.cnblogs.com/huangxincheng/archive/2012/04/03/2430638.html