常見的非同步方式async 和 await

来源:https://www.cnblogs.com/Nobel/archive/2018/08/19/9501576.html
-Advertisement-
Play Games

之前研究過c#的async和await關鍵字,幕後幹了什麼,但是不知道為什麼找不到相關資料了。現在重新研究一遍,順便記錄下來,方便以後查閱。基礎知識async 關鍵字標註一個方法,該方法返回值是一個Task、或者Task、void、包含GetAwaiter方法的類型。該方法通常包含一個await表達... ...


之前研究過c#的async和await關鍵字,幕後幹了什麼,但是不知道為什麼找不到相關資料了。現在重新研究一遍,順便記錄下來,方便以後查閱。

基礎知識

async 關鍵字標註一個方法,該方法返回值是一個Task、或者Task<TResult>、void、包含GetAwaiter方法的類型。該方法通常包含一個await表達式。該表達式標註一個點,將被某個非同步方法回跳到該點。並且,當前函數執行到該點,將立刻返回控制權給調用方。

以上描述了async方法想乾的事情,至於如何實現,這裡就不涉獵了。

個人見解

由此可以知道,async 和await關鍵字主要目的是為了控制非同步線程的同步,讓一個非同步過程,表現得好像同步過程一樣。

比如async 方法分n個任務去下載網頁併進行處理:先await下載,然後立刻返回調用方,之後的處理就由非同步線程完成下載後調用。這時候調用方可以繼續執行它的任務,不過,如果調用方立刻就需要async的結果,那麼應該就只能等待,不過大多數情況:他暫時不需要這個結果,那麼就可以並行處理這些代碼。

可見,並行性體現在await 上,如果await 點和最終的數據結果距離越遠,那麼並行度就越高。如果await的點越多,相信也會改善並行性。

資料顯示,async 和await 關鍵字並不會創建線程,這是很關鍵的一點。他們只是創建了一個返回點,提供給需要他的線程使用。那麼線程究竟是誰創建?註意await 表達式的組成,他需要一個Task,一個Task並不代表一定要創建線程,也可以是另一個async方法,但是層層包裹最裡面的方法,很可能就是一個原生的Task,比如await Task.Run(()=>Thread.Sleep(0)); ,這個真正產生線程的語句,就會根據前面那些await點,逐個回調。

從這點來看,async 方法,未必就是一個非同步方法,他在語義上更加貼近“非阻塞”, 當遇到阻塞操作,立刻用await定點返回,至於其他更深一層的解決手段,它就不關心了。這是程式員需要關心的,程式員需要用真正的創建線程代碼,來完成非同步操作(當然這一步可由庫程式員完成)。

註意async的幾個返回值類型,這代表了不同的使用場景。如果是void,說明客戶端不關心數據同步問題,它只需要線程的控制權立刻返回。可以用在ui 等場合,如果是Task,客戶端也不關心數據,但是它希望能夠控制非同步線程,這可能是對任務執行順序有一定的要求。當然,最常見的是Task<TResult>。

綜上,async和await並不是為了多任務而設計的,如果追求高併發,應該在async函數內部用Task好好設計一番。在使用async 和await的時候,只需要按照非阻塞的思路去編寫代碼就可以了,至於幕後怎麼處理就交給真正的多線程代碼創建者吧。

示範代碼

        static async Task RunTaskAsync(int step)
        {
            for(int i=0; i < step; i++)
            {
                await Task.Run(()=>Thread.Sleep(tmloop));//點是靜態的,依次執行
                Thread.Sleep(tm2);
            }
            Thread.Sleep(tm3);
        }

//客戶端
            Task tk= RunTaskAsync(step);
            Thread.Sleep(tm1);//這一段是並行的,取max(函數,代碼段)最大時間
            tk.Wait( );//這裡代表最終數據

為了達到高度並行,應該用真正的多線程代碼:

        static async Task RunTaskByParallelAsync(int step)
        {
            await Task.Run(()=>Parallel.For(0,step,
                s=>{loop(tmloop);
                    loop(tm2);
                    }
            ));
            loop(tm3);
        }

並行編碼方法

並行執行有幾個方法,第一個是創建n個Task,一起啟動。問題是怎麼處理await點。每個task寫一個await點是不行的,因為遇到第一個await就立刻返回,而不會開啟所有任務並行執行。因此await不能隨便放。那麼如何為一組Task設定await點呢?可以通過Task.WhenAll 這個方法,他會等待一組Task執行完畢返回。

特定情況下,可以用Parallel.For 來開啟一組任務,但是這個類並沒有實現async模式,也就是它會阻塞當前線程,所以需要用一個Task來包裹它。

可見,非阻塞和並行不完全是一回事。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 接上一篇,前兩篇解決中文的問題主要是在字元集上做的手腳,即將中文轉成英文,但是有一種情況我們都來不及做轉換,即登錄時伺服器直接返回了中文內容: 此時程式報瞭如下錯誤,其實還是字元集問題: 為此:我們可以在接收數據的時候直接對其進行異常捕捉,如果異常則換一種解碼方式: 上一篇:ssh.invoke_s ...
  • 信號signal 是python進程間進行信號發送的一種機制,其原理是操作系統對進程的控制,是一種程式中斷 一個進程一旦接收到信號就會打斷原來的程式執行流程來處理信號。 那麼singanl到底有什麼用呢? siganl的應用: 1. 故障定位技術(進程的底層故障,例如進程突然中斷和一些可能性較小的故 ...
  • luogu原題 最近剛學了博弈論,拿來練練手qwq 其實和數值的大小並沒有關係 我們用$N/P$態來表示必勝/必敗狀態 先在草稿紙上探究硬幣在最左側(其實左右側是等價的)的一條長鏈的$N/P$態,設鏈長為$n$ 我們用$1$代替其他所有非$0$數 $n=2: 11$ $N$態 $n=3: 111$ ...
  • 近一個月一直在寫業務,空閑時間刷刷leetcode,刷題過程中遇到了一道比較有意思的題目,和大家分享。 題目描述: 給定兩個整數,被除數 dividend 和除數 divisor。將兩數相除,要求不使用乘法、除法和 mod 運算符。返回被除數 dividend 除以除數 divisor 得到的商。 ...
  • 廢話不說,直接開門見山! 需要在WebContent下的lib下導入兩個包 mybatis-3.2.5.jar ojdbc6.jar 1 package com.xdl.entity; 2 3 import java.io.Serializable; 4 5 public class Dept im ...
  • 使用mapper代理方式開發: 需要編寫mapper介面,UserMapper.java需要編寫映射文件,UserMapper.xml需要遵循一些開發規範,mybatis便可以自動生成mapper介面實現類代理對象 遵循的開發規範:1:UserMapper.xml中namespace命名空間 與 U ...
  • CLR線程池並不會在CLR初始化時立即建立線程,而是在應用程式要創建線程來運行任務時,線程池才初始化一個線程。線程池初始化時是沒有線程的,線程池裡的線程的初始化與其他線程一樣,但是在完成任務以後,該線程不會自行銷毀,而是以掛起的狀態返回到線程池。直到應用程式再次向線程池發出請求時,線程池裡掛起的線程 ...
  • 概述 Windows Community Toolkit 4.0 於 2018 月 8 月初發佈:Windows Community Toolkit 4.0 Release Note. 4.0 版本相較於 3.0,增加了 DataGrid 等控制項,Sample App 支持了 Fluent Desi ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...