namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
int a = 0;
Task task = Task.Run(() => dowork(
ref a));
Console.WriteLine(a);
}
static void dowork(ref int a)
{
a = 2;
Console.WriteLine(a);
}
}
}
為什么輸出是0,2不是2,2
uj5u.com熱心網友回復:
int a = 0;Task task = Task.Run(() => dowork(
ref a));
Console.WriteLine(a);
主執行緒開出task任務后,馬上去執行下一句Console.WriteLine(a);不管task執行緒了,task自己執行自己的
順序:
static void Main(string[] args)
{
1、int a = 0;
2、Task task = Task.Run(() => dowork(
ref a));
3、 Console.WriteLine(a);
}
static void dowork(ref int a)
{
a = 2;
4、Console.WriteLine(a);
}
uj5u.com熱心網友回復:
0是Main輸出的;2是由Task輸出的Task執行不阻塞主執行緒
要嚴格控制執行順序,需要使用信號量或者其他的同步方法
uj5u.com熱心網友回復:
那怎么修改才能輸出2,2uj5u.com熱心網友回復:
輸出 0,2 還是 2,2 這從設計上來說,是不確定的。不能想當然地說“輸出什么、不輸出什么”,因為這兩段代碼是并發的!uj5u.com熱心網友回復:
很簡單,這樣寫代碼
static void Main(string[] args)
{
int a = 0;
dowork(ref a);
Console.WriteLine(a);
}
static void dowork(ref int a)
{
a = 2;
Console.WriteLine(a);
}
不要自己明明是并發多執行緒操作,又來問“怎么產生不并發多執行緒的結果”。那就是為了 Task 而 Task 地寫代碼,多此一舉了。
uj5u.com熱心網友回復:
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
int a = 0;
Task task = Task.Run(() => dowork(
ref a));
task.Wait();
Console.WriteLine(a);
}
static void dowork(ref int a)
{
a = 2;
Console.WriteLine(a);
}
}
}
uj5u.com熱心網友回復:
從執行緒池中分配的Task是不會阻塞主執行緒的(除非顯示阻塞)。代碼的順序執行繼續進行,也就是task執行之后 是不影響后邊代碼的輸出,也就是“異步”了。學習它的用法:https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx 不僅要會用,更要知道什么情況下可以用。
uj5u.com熱心網友回復:
你跑了一個任務,所以輸出0或者2都是可能的。
因為主執行緒和task是并發執行的。
至于是不是要讓任務執行先輸出,可以wait
uj5u.com熱心網友回復:
我運行時出現了好幾次2,0uj5u.com熱心網友回復:
沒有運行順序,windows上執行緒的基礎就是他沒順序,不然執行緒的就不會那么讓新手為難了因為開執行緒簡單,任何新人想開就開,但是執行緒同步,信號量控制,執行緒間通訊,背景關系控制才是執行緒的難以讓新手使用的關鍵
否則那些基礎書,也不會再執行緒章節3,4頁紙就告訴你執行緒是啥,怎么開執行緒。然后再花30,40頁紙告訴你怎么進行執行緒同步,執行緒調度,執行緒排程,執行緒間通訊了
同樣的代碼也證明了,為啥需要上鎖,為啥需要執行緒安全類物件的原因了,因為他無序,你無法保證他就一定向你想的那樣運行
uj5u.com熱心網友回復:
你出現0,2是只取決于背景關系運行的快慢,不取決于他運行的順序。樓上幾位寫wait,是同步,強制讓他先運行完
而如果
int a = 0;
Task task = Task.Run(() => dowork(
ref a));
for(i=0;i<100;i++) //你要故意讓外面比執行緒運行的慢,那么他就是2,2
{
}
Console.WriteLine(a);
uj5u.com熱心網友回復:
主執行緒不管Task,所以直接0,2 你可以加控制 Task完了再執行后續操作 task.Wait() 可以做到uj5u.com熱心網友回復:
隨機的.并不能確定運行順序,如果你需要先運行A,再運行B的話。用ContinueWith
如果你想全部運行完再運行某個東西的話。用whenAll
uj5u.com熱心網友回復:
這是個好問題。Task.Run開啟了一個新的執行緒,并且,run開始任務后不阻塞主執行緒,主執行緒不管run中的任務完成與否就進行下面的任務,所以,main方法中的Console.WriteLine(a);是要先于run子執行緒任務的完成而執行的,此時子執行緒方法dowork還沒有被 呼叫,自然a值是0,所以輸出0,隨后子執行緒執行了a = 2;這個動作,這時的a的值才變為2。如果要輸出2,那么就需要主執行緒來等待子執行緒執行完成后再執行下面的Console.WriteLine(a),方法是task.Wait();
這樣main方法中的代碼就改為如下:
int a = 0;
Task task = Task.Run(() => dowork( ref a));
task.Wait();//等待任務完成再執行下面的代碼,如果不加這一句,那么下面的代碼將在任務完前就執行了。
Console.WriteLine(a);
總結一下就是:Task.Run 中的方法開啟了新的執行緒,并且在主執行緒中不特別指定等待它完成的情況下,主執行緒是不會被阻塞(所以叫異步),而在task.Wait();方法明確指定主執行緒需要子執行緒完程后才執行后面代碼的情況下,這時就變成了同步。
總體來說,多執行緒確實是比較繞的,這源于計算機作業原理的博大精深。剛開始學習時我自己把異步、同步和同時的概念總是分不清楚。初步理解的話可以認為異步就是同時進行任務,誰也不等誰,而同步是我們沒有多執行緒時學習的,它反而是不同時,就是后面的代碼一定要等前面的代碼執行完才執行。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/107485.html
標籤:C#
