iT邦幫忙

0

async/await,await代表等待非同步執行完才會執行下一段嗎?

請問大大們,如題
1.await是否代表等待非同步執行完才會執行下一段呢?
2.如果await是否代表等待非同步執行完才會執行下一段,那這樣的話跟同步的程式有何差別?
下面第一段程式註解看起來是這個意思,但也看了其它async/await的文章,有些感覺await關鍵字並不是用來表示需等待非同步執行完才會執行下一段的意思,只是一個呼叫非同步方法的一個關鍵字。
上來再三確認一下await是否代表呼叫非同步執行同時也需等待非同步執行完才會執行下一段呢~

private async void btnThread6_Click(object sender, EventArgs e)
{
    //Task<int> measn it will return an it when finish the Task.
    //This Task<int> task is actually pointing to SlowFunc() function
    Task<int> task = new Task<int>(SlowFunc);
    task.Start();
    lbl1.Text = "Processing...";
    //.Net will use some special algorism to avoid blocking and
    //Wait until the SlowFunc() task completes.
    int outputInt = await task;
    lbl1.Text = $"outputInt=={outputInt}";
}

這裡的await是否也代表等待first執行完才會執行下一段second呢?

// Serial execution
public async Task<List<Thing>> GetThings()
{
    var first = await GetExpensiveThing();
    var second = await GetExpensiveThing();
    return new List<Thing>() { first, second };
}

以下這段taskA.Wait();感覺才是等待非同步執行完才會執行下一段

public static void Main()
{
  Thread.CurrentThread.Name = "Main";
  // Define and run the task.
  Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));
  // Output a message from the calling thread.
  Console.WriteLine("Hello from thread '{0}'.",
                      Thread.CurrentThread.Name);
  taskA.Wait();
}

以下這段theTask.Result;也可以用來等待非同步執行完才會執行下一段

static string DownloadSource(string url)
{
    using (HttpClient httpClient = new HttpClient())
    {
        Console.WriteLine($"Getting source for {url}");
        Task<string> theTask = httpClient.GetStringAsync(url);
        string source = theTask.Result;
        Console.WriteLine($"Finished getting source for {url}");
        return source;
    }
}

Task.WaitAll;也可以用來等待非同步執行完才會執行下一段

void Main()
{
	var task1 = Task.Run(() => Task1());
	var task2 = Task.Run(() => Task2());
	var task3 = Task.Run(() => Task3());
	Task.WaitAll(task1,task2,task3); //在此等待所有任務結果,才繼續往下執行
	Console.WriteLine("completed task");
}

另外請教
Task 是屬於非同步
Parallel 是屬於多執行緒
以上認知不知是否正確?

Parallel範例

static void Main(string[] args)
{
    var sw = new Stopwatch();
    sw.Start();
    const int numParts = 10;
    var primes = new List<int>[numParts];
    Parallel.For(0, numParts, i => primes[i] = GetPrimeNumbers(i == 0 ? 2 : i * 1000000 + 1, (i + 1) * 1000000));
    var result = primes.Sum(p => p.Count);
    Console.WriteLine("Total prime numbers: {0}\nProcess time: {1}", result, sw.ElapsedMilliseconds);
}
4
japhenchen
iT邦大師 1 級 ‧ 2021-06-30 11:51:46
最佳解答

不專業的簡單回答

有些函數類別命令....大部份預設是以同步方式設計,也就是說每一行都要確實完成才會執行下一行,當然有同步就有非同步的命令類別函數....像是網路IO大部份都會做非同步async模式來運作(網路的狀況千奇百怪咩),一般熟練的會用委派去接後續的工作,但也會發生多個工作之間有所謂的依賴性,後面的程式,依賴上段程式的回傳結果,哪怕是網路,再久也要await .... 於是就有用await把非同步工作做成同步模式等待回應

反之,也有同步的命令類別函數,在你的程式設計裡就不想去等待那些工作結束,想要讓他射後不理,除了委派,也能以task方式做成非同步化,這樣就能避免程式因為IO的問題造成死鎖(沒有回應)

非同步化算是多執行緒的應用其中一種,多執行緒的範圍很廣,像上述講的同步與非同步是其中一小部份而已,在程式上做timer、backgroundwork這種背景作業也算一種,還有一種比較常見的就是壓搾資源型的多工,像網路爬蟲(同時有多隻蟲在執行)或挖礦機,每條緒(這裡不一定是緒,要看作業系統跟處理器怎麼分配)執行工作各自獨立也互不干擾,有沒有執行完得到什麼結果,都會讓各工作自行負責,只要回報給主程序執行結果就好..

至於作業系統+處理器是以分時多工或真實多工或其他多工,就有不同的表現方式......對程式設計者而言,影響不大,頂多是效能讓你看出來而已..除非,你要做到很底層,指派哪個處理器來執行工作,那又是另一個領域的事了(仰天長嘆)

看更多先前的回應...收起先前的回應...
leo226 iT邦新手 4 級 ‧ 2021-06-30 21:25:31 檢舉

感謝大大回覆~
其中有一點需討論,[非同步化算是多執行緒的應用其中一種]
就我最近研究非同步相關議題的部份,其中有提到非同步化並不算是多執行緒,非同步並不會建立執行緒來執行,主要是使用來不佔用主執行緒的狀況,讓程式在背景執行,讓主執行緒可以正常運作。
以上是我目前理解的狀況~有錯麻煩指正~

huangsb iT邦好手 1 級 ‧ 2021-07-01 06:59:14 檢舉

以 C# 來說,Task 是屬於非同步的方式,還算是多執行緒,但不是直接管理多執行緒,程式碼會比較好寫,不容易出錯。

我有說到是否為多執行緒,還得由作業系統與處理器來決定,並非所有平台都真的以多緒或分時處理,沒有統一定也沒有"定義"

btw ... 非同步/異步,就是另外開一條工作線去處理後續的工作,不會死鎖主程式,主程式會繼續進行其他的工作,同時間可以跑多少個TASK?看電腦資源夠不夠,我在i5 8GB的機器上最多跑16個TASK,是不是thread ? 這個線上手冊上並沒有說明,也有第三方類庫可用,是否為thread .. 天知道.. 用spy64去監看吧

至於同步,非得要用的情況依舊存在,只要有往上依賴的工作,如.......下載一個檔案,解壓縮,讀取內容,統計總數,再寫回資料庫,且用戶不會因為死鎖無回應而手忙腳亂的,我就會做成同步,省的還要開一堆TASK去跑

Apache / iis / nginx / node.js ....這類web server也能算是多工多緒的應用,每個連接(session)都是一個各自獨立的工作,是否佔用一個執行緒,如何分配在哪個處理器上執行,這真的也沒有一個統一的定義去解釋,那要是在單核單緒處理器上執行,又該如何工作,相信作業系統自會有一套多工的解決方案,才不會因為一堆CPU架構而自亂陣腳吧

leo226 iT邦新手 4 級 ‧ 2021-07-04 20:07:36 檢舉

自己做了些測試,如大大所言,非同步的方法中確實也會開多個執行緒,若Thread pool有閒置的Thread,則會拿來reuse。
感謝前輩們經驗分享~

2
Todd
iT邦新手 4 級 ‧ 2021-07-01 00:31:47

雖然沒標注語言,看起來也不太像JS
但如果以JS的概念來解釋的話

  1. 因為在js的執行緒中有分 macroTask(setTimeout之類的瀏覽器提供的web api)及mircoTask,而在event loop中,一次只會消化一個macroTask且清完mircoTask Queue 才會進到下一次循環
    然後又因為js本身是單執行緒語言,所以避免阻塞主執行緒會把耗時的macroTask移到其他執行緒(像是瀏覽器)執行,但如果這個macroTask會影響到之後的行為那我們就必須利用await/promise之類的方式直到這個回傳後才能執行下一步。
    所以意思是我們可以「把非同步的行為,用類似同步的寫法去處理」

1
u2420123
iT邦新手 3 級 ‧ 2021-07-01 10:29:43
  1. 同步意思是 你執行拋出一個請求"不等待" 繼續往下執行其他函式或動作, 這叫同步
  2. 我們常常說 非同步(async), 你執行一個動作, 需等待請求回應(await)
    你才做下一步
1
I code so I am
iT邦高手 1 級 ‧ 2021-07-02 00:40:14

Q:如果await是否代表等待非同步執行完才會執行下一段,那這樣的話跟同步的程式有何差別?
A:有兩種差別。

  1. task.Start()、await之間還可做很多與task無關順序的事,例如print、更新畫面。
  2. 可一次丟出很多tasks,await可以等這些tasks全處理完,類似 thread 的 join。
leo226 iT邦新手 4 級 ‧ 2021-07-04 20:04:48 檢舉

了解,感謝前輩指點~

1
石頭
iT邦高手 1 級 ‧ 2021-07-03 17:44:27

我建議你可以看一下MSDN裡面有一系列介紹async/await和非同步相關文章

https://docs.microsoft.com/zh-tw/dotnet/csharp/async

看你目前的提問建議先理解
甚麼是
I/O bound
CPU bound

後面在來探討後面的東西.

await是一個語法糖她做的事情非常多.

1.await是否代表等待非同步執行完才會執行下一段呢?

Ans:需要等待Task完成才會執行後續程式.

2.如果await是否代表等待非同步執行完才會執行下一段,那這樣的話跟同步的程式有何差別?

那是因為目前的範例你是在呼叫async方法後直接await看不出區別,如果你嘗試跑下面這個程式碼應該可以比較能理解差別了.

HttpClient hc = new HttpClient();
var t1 = hc.GetAsync("https://www.google.com");
var t3 = hc.GetAsync("https://www.yahoo.com");

var r3 = await t3;
var r1 = await t1;
leo226 iT邦新手 4 級 ‧ 2021-07-04 20:05:08 檢舉

了解,感謝前輩指點~

我要發表回答

立即登入回答