第46篇 多線程如何排隊執行
有一個這樣場景,程序會有一個非常耗時的操作,但要求耗時的操作完成後,再順序的執行一個不耗時的操作,而且這個程序的調用,可能存在同時調用的情況。
具體的模型如下:
從Start開始觸發了5個線程,經過一個longTimeJob同時執行,我們不關心longJob的執行時間和先後順序,根據Start的先後順序來執行一個ShortJob。下面我們用代碼來模擬上面的過程。
舉例說明:有ABCD 4個線程,進入的順序也是ABCD,A耗時3s,B耗時7s,C耗時1s,D耗時3s. 所以如果當4個線程都同時開始執行時,完成的先後順序為 CADB,但我們要求的順序是ABCD,也就是說C要等待AB執行完後,才能繼續後續的工作。
我們可以用請求bing搜索來模擬longTimeJob,根據傳入的序列來決定請求多少次,主要模擬方法如下:
private static async Task Test
{
var arry = new
{
10, 9, 8, 7, 6, 5, 4, 3, 2, 1
};
var listTask = new List
foreach (var i in arry)
{
var i1 = i;
var task = Task.Run( => DoJob(i1));
listTask.Add(task);
}
foreach (var task in listTask)
{
Console.WriteLine("輸出-->:" + await task);//
}
}
public static Task
{
return Task.Run( =>
{
DoLongTimeThing(o);
return o;
});
}
public static void DoLongTimeThing(int i)
{
Console.WriteLine("執行-->:" + i);
for (int j = 0; j < i; j++)
{
HttpGet("http://cn.bing.com/");
}
Console.WriteLine("執行完畢-->:" + i);
}
public static string HttpGet(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse;
StreamReader reader = new StreamReader(response.GetResponseStream, Encoding.UTF8);
string content = reader.ReadToEnd;
return content;
}
catch (Exception e)
{
return e.Message;
}
}
執行結果:
上面的代碼大概能解決我們的問題,有一個問題,對於客戶的調用我們無法形成一個List,而且list是線程安全的,所以針對上述的方法在實際的業務場景中無法使用。
新思路我們無法實現一個有序的Task列表,如果換一個角度考慮,當一個任務形成的時間,同時生成一個對應的HashCode,對HashCode進行一個隊列的入隊操作,當執行完成longTimeJob後,判斷是不是隊列的第一個Task的HashCode,如果是則執行,如果不是則繼續等待,切換線程。 具體如下思路如下圖:
public static Queue
static void Main(string[] args)
{
var arry = new
{
10, 9, 8, 7, 6, 5, 4, 3, 2, 1
};
foreach (var i in arry)
{
Console.WriteLine("進入Job順序-->:" + i);
Test(i);
}
Console.ReadKey;
}
public static void Test(int i)
{
var taskId = Guid.NewGuid.ToString;
Queue.Enqueue(taskId);
Task.Factory.StartNew(DoJob, new object[] { i, taskId });
}
public static void DoJob(object o)
{
var oArry = (object[])o;
var n = (int)oArry[0];
var currId = oArry[1].ToString;
DoLongTimeThing(n);//
while (currId != Queue.Peek)
{
Thread.Sleep(1);//等線程切換
}
Console.WriteLine("DoShortJob輸出-->:" + n);//
//請求資料庫
Queue.Dequeue;
}
public static void DoLongTimeThing(int i)
{
Console.WriteLine("LongTimeJob執行-->:" + i);
for (int j = 0; j < i; j++)
{
HttpGet("http://cn.bing.com/");
}
Console.WriteLine("LongTimeJob執行完畢-->:" + i);
}
public static string HttpGet(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse;
StreamReader reader = new StreamReader(response.GetResponseStream, Encoding.UTF8);
string content = reader.ReadToEnd;
return content;
}
catch (Exception e)
{
return e.Message;
}
}
運行結果如下:
雖然執行結果看起來很亂,但仔細比對可以發現最終的DoShortTime是按順序執行的。


※淺從System.Web.Http.Owin的HttpMessageHandlerAdapter看適配器模式
※TP5 面向對象和命名空間
※gdb常用命令及使用gdb調試多進程多線程程序
※WindowManager.LayoutParams的探究
TAG:達人科技 |
※線程撕裂者2990X跑分曝光 32核64線程無敵
※蘋果A12性能殘暴 單線程5200分多線程13000分
※AMD二代線程撕裂者8月13日發布:最多32核心64線程
※C++11多線程 多線程傳參詳解
※第405期:線程撕裂者渲染PC
※AMD線程撕裂者二代擴軍:24核心48線程只要9999
※疑似線程撕裂者三代跑分曝光 16核心32線程
※線程撕裂者奪冠!2018年硬體排行榜:GTX1060最受歡迎
※超線程成棄兒?九代酷睿9000系列規格令人鬱悶
※新一代線程撕裂者曝光 32核64線程只是入門?
※九代酷睿9000系列規格曝光:超線程成棄兒
※撕裂者2990X現身:32核64線程
※32核心64線程!AMD線程撕裂者二代旗艦2990X現身:加速4GHz
※8核心16線程第九代酷睿i7 9700k,10nm?不一定
※英特爾第十代U系列處理器曝光:i7-10710U為6核12線程
※32核64線程!AMD新一代撕裂者8月13日起售
※銳龍7 2800X現身,10核20線程
※六核12線程 火影 地獄火X6促銷6699元
※16核32線程銳龍R9-3950X已經很強 但AMD還有64核128線程的王牌
※Exynos 9810跑分成績出爐:單線程破四千多核破萬