Megosztás a következőn keresztül:


Tevékenység aszinkron programozási modellje

Elkerülheti a teljesítmény szűk keresztmetszeteit, és aszinkron programozással javíthatja az alkalmazás általános válaszkészségét. Az aszinkron alkalmazások írásának hagyományos technikái azonban bonyolultak lehetnek, ami megnehezíti az írást, a hibakeresést és a karbantartást.

A C# támogatja az egyszerűsített megközelítést, az aszinkron programozást, amely a .NET-futtatókörnyezet aszinkron támogatását használja. A fordító elvégzi a fejlesztő által korábban végzett nehéz munkát, és az alkalmazás megőrzi a szinkron kódhoz hasonló logikai struktúrát. Ennek eredményeképpen az aszinkron programozás minden előnyét megkapja az erőfeszítés töredékével.

Ez a témakör áttekintést nyújt az aszinkron programozás használatának időpontjáról és módjáról, valamint a részleteket és példákat tartalmazó támogatási témakörökre mutató hivatkozásokat tartalmaz.

Az Async javítja a válaszkészséget

Az aszinkronizálás elengedhetetlen a potenciálisan blokkoló tevékenységekhez, például a webes hozzáféréshez. A webes erőforrásokhoz való hozzáférés néha lassú vagy késleltetett. Ha egy ilyen tevékenység szinkronizált folyamatban van letiltva, a teljes alkalmazásnak várnia kell. Aszinkron folyamatban az alkalmazás folytathatja a webes erőforrástól nem függő egyéb munkát, amíg a potenciálisan blokkoló tevékenység be nem fejeződik.

Az alábbi táblázat azokat a tipikus területeket mutatja be, ahol az aszinkron programozás javítja a válaszkészséget. A .NET-ből származó felsorolt API-k és a Windows-futtatókörnyezet olyan metódusokat tartalmaznak, amelyek támogatják az aszinkron programozást.

Alkalmazásterület .NET-típusok aszinkron metódusokkal Windows-futtatókörnyezet aszinkron metódusokkal rendelkező típusok
Webes hozzáférés HttpClient Windows.Web.Http.HttpClient
SyndicationClient
Fájlok használata JsonSerializer
StreamReader
StreamWriter
XmlReader
XmlWriter
StorageFile
Képek használata MediaCapture
BitmapEncoder
BitmapDecoder
WCF-programozás Szinkron és aszinkron műveletek

Az aszinkronizálás különösen hasznosnak bizonyul a felhasználói felületi szálhoz hozzáférő alkalmazások számára, mivel a felhasználói felülettel kapcsolatos összes tevékenység általában egy szálon osztozik. Ha egy szinkron alkalmazásban bármely folyamat le van tiltva, az összes le lesz tiltva. Az alkalmazás nem válaszol, és arra következtethet, hogy nem sikerült, ha inkább csak várakozik.

Ha aszinkron metódusokat használ, az alkalmazás továbbra is válaszol a felhasználói felületre. Átméretezhet vagy kis méretűvé tehet például egy ablakot, vagy bezárhatja az alkalmazást, ha nem szeretné megvárni, amíg befejeződik.

Az aszinkron megközelítés hozzáadja az automatikus átvitel megfelelőit az aszinkron műveletek tervezésekor választható lehetőségek listájához. Ez azt jelent, hogy a hagyományos aszinkron programozás minden előnyét megkapja, de sokkal kevesebb erőfeszítést igényel a fejlesztőtől.

Az aszinkron metódusok könnyen írhatóak

Az aszinkron és a várakozási kulcsszavak a C#-ban az aszinkron programozás középpontjában állnak. A két kulcsszó használatával a .NET-keretrendszer, a .NET Core vagy a Windows-futtatókörnyezet erőforrásaival szinte ugyanolyan egyszerűen hozhat létre aszinkron metódust, mint egy szinkron metódust. A kulcsszóval async definiált aszinkron metódusokat aszinkron metódusnak nevezzük.

Az alábbi példa egy aszinkron metódust mutat be. A kód szinte minden elemének ismerősnek kell lennie.

Egy teljes Windows megjelenítési alaprendszer (WPF) példa érhető el az Aszinkron programozásból az aszinkron programból való letöltéshez, és várja a C#-ban.

public async Task<int> GetUrlContentLengthAsync()
{
    using var client = new HttpClient();

    Task<string> getStringTask =
        client.GetStringAsync("https://learn.microsoft.com/dotnet");

    DoIndependentWork();

    string contents = await getStringTask;

    return contents.Length;
}

void DoIndependentWork()
{
    Console.WriteLine("Working...");
}

Az előző mintából számos gyakorlatot ismerhet meg. Kezdje a metódus aláírásával. Tartalmazza a async módosító. A visszatérési típus ( Task<int> további beállításokért lásd a "Visszatérési típusok" szakaszt). A metódus neve a következő lesz Async: . A metódus GetStringAsyncTask<string>törzsében egy . Ez azt jelenti, await hogy amikor a feladat kap egy string (contents). Mielőtt megvárja a feladatot, olyan munkát végezhet, amely nem támaszkodik a string forrásra GetStringAsync.

Ügyeljen az operátorra await . Felfüggeszti a következőt GetUrlContentLengthAsync:

  • GetUrlContentLengthAsync nem folytatható, amíg getStringTask be nem fejeződik.
  • Eközben az irányítás visszatér a hívóhoz GetUrlContentLengthAsync.
  • A vezérlő itt folytatódik, ha getStringTask befejeződött.
  • Az await operátor ezután lekéri az eredményt a string következőből getStringTask: .

A visszatérési utasítás egész számot ad meg. A hosszérték lekérésére váró GetUrlContentLengthAsync metódusok.

Ha GetUrlContentLengthAsync nem rendelkezik olyan munkával, amelyet a hívás GetStringAsync és a befejezésre várás között el tud végezni, leegyszerűsítheti a kódot a következő egyetlen utasítás meghívásával és várakozásával.

string contents = await client.GetStringAsync("https://learn.microsoft.com/dotnet");

Az alábbi jellemzők összefoglalják, hogy mi teszi az előző példát aszinkron metódussá:

  • A metódus-aláírás tartalmaz egy async módosítót.

  • Az aszinkron metódus neve konvenció szerint "Async" utótaggal végződik.

  • A visszatérési típus az alábbi típusok egyike:

    • Task<TResult> ha a metódus olyan visszatérési utasítással rendelkezik, amelyben az operandus típusa TResultszerepel.
    • Task ha a metódus nem rendelkezik visszatérési utasítással, vagy egy operandus nélküli visszatérési utasítással rendelkezik.
    • void ha aszinkron eseménykezelőt ír.
    • Bármely más típus, amely rendelkezik metódussal GetAwaiter .

    További információ: Return types and parameters section.

  • A metódus általában tartalmaz legalább egy await kifejezést, amely azt a pontot jelöli, ahol a metódus nem folytatható, amíg a várt aszinkron művelet be nem fejeződik. Addig is a metódus fel van függesztve, és a vezérlő visszatér a metódus hívójához. A témakör következő szakasza bemutatja, mi történik a felfüggesztési ponton.

Az aszinkron metódusokban a megadott kulcsszavakat és típusokat használva jelezheti, hogy mit szeretne tenni, a fordító pedig elvégzi a többit, beleértve annak nyomon követését, hogy mi történjen, amikor a vezérlő visszatér egy felfüggesztett metódus várakozási pontjára. Bizonyos rutinfolyamatok, például a hurkok és a kivételkezelés nehézkesen kezelhetők a hagyományos aszinkron kódban. Az aszinkron metódusban ezeket az elemeket ugyanúgy kell megírni, mint egy szinkron megoldásban, és a probléma megoldódott.

A .NET-keretrendszer korábbi verzióiban használt aszinkronságról további információt a TPL és a hagyományos .NET-keretrendszer aszinkron programozás című témakörben talál.

Mi történik az aszinkron metódusban?

Az aszinkron programozásban az a legfontosabb, hogy a vezérlőfolyamat hogyan változik metódusról metódusra. A következő diagram végigvezeti a folyamaton:

Trace navigation of async control flow

A diagramban szereplő számok a következő lépéseknek felelnek meg, amikor egy hívó metódus meghívja az aszinkron metódust.

  1. A hívó metódus meghívja és várja az aszinkron GetUrlContentLengthAsync metódust.

  2. GetUrlContentLengthAsync létrehoz egy példányt HttpClient , és meghívja az aszinkron GetStringAsync metódust egy webhely tartalmának sztringként való letöltéséhez.

  3. Valami történik, GetStringAsync ami felfüggeszti az előrehaladását. Lehet, hogy várnia kell egy webhely letöltésére vagy más blokkoló tevékenységre. Az erőforrások GetStringAsync blokkolásának elkerülése érdekében szabályozza a hívót. GetUrlContentLengthAsync

    GetStringAsync visszaad egy Task<TResult>, ahol TResult egy sztring, és GetUrlContentLengthAsync hozzárendeli a feladatot a getStringTask változóhoz. A feladat a hívás GetStringAsyncfolyamatban lévő folyamatát jelöli, és a munka befejezésekor egy tényleges sztringérték létrehozására vonatkozó kötelezettségvállalással rendelkezik.

  4. Mivel getStringTask még nem várták meg, folytathatja azokat a munkát, GetUrlContentLengthAsync amelyek nem függnek a végeredménytől GetStringAsync. Ezt a munkát a szinkron metódus DoIndependentWorkhívása jelöli.

  5. DoIndependentWork egy szinkron metódus, amely elvégzi a munkáját, és visszatér a hívóhoz.

  6. GetUrlContentLengthAsyncelfogyott a munka, hogy nem tud eredményt.getStringTask GetUrlContentLengthAsync ezután ki szeretné számítani és visszaadni a letöltött sztring hosszát, de a metódus csak akkor tudja kiszámítani ezt az értéket, ha a metódus tartalmazza a sztringet.

    Ezért egy várakozó operátort használ a folyamat felfüggesztéséhez, GetUrlContentLengthAsync és a hívott GetUrlContentLengthAsyncmetódushoz való hozzáférés szabályozására. GetUrlContentLengthAsync a hívónak ad vissza egy Task<int> értéket. A feladat ígéretet jelent egy egész szám eredményének létrehozására, amely a letöltött sztring hossza.

    Feljegyzés

    Ha GetStringAsync (és ezért getStringTask) befejeződik, mielőtt GetUrlContentLengthAsync megvárja, az irányítás a következőben GetUrlContentLengthAsyncmarad: . Ha az úgynevezett aszinkron folyamat getStringTask már befejeződöttGetUrlContentLengthAsync, és nem kell várnia a végeredményre, a felfüggesztés, majd a visszatérés GetUrlContentLengthAsync költsége kárba vész.

    A hívó metóduson belül a feldolgozási minta folytatódik. Előfordulhat, hogy a hívó más olyan munkát végez, amely nem függ az eredménytől GetUrlContentLengthAsync , mielőtt az eredményre várna, vagy a hívó azonnal várakozhat. A hívási metódus várakozik GetUrlContentLengthAsync, és GetUrlContentLengthAsync a következőre GetStringAsyncvár.

  7. GetStringAsync befejezi és sztringeredményt hoz létre. A sztring eredményét a hívás GetStringAsync nem a várt módon adja vissza. (Ne feledje, hogy a metódus már visszaadott egy feladatot a 3. lépésben.) Ehelyett a sztring eredménye abban a feladatban lesz tárolva, amely a metódus befejezését jelöli. getStringTask A várakozás operátor a következőből getStringTaskkéri le az eredményt: . A hozzárendelési utasítás a lekért eredményt a következőhöz contentsrendeli: .

  8. Ha GetUrlContentLengthAsync a sztring eredménye van, a metódus kiszámíthatja a sztring hosszát. Ezután a munka GetUrlContentLengthAsync is befejeződött, és a várakozó eseménykezelő újraindulhat. A témakör végén található teljes példában megerősítheti, hogy az eseménykezelő lekéri és kinyomtatja a hosszeredmény értékét. Ha még csak most ismerkedik az aszinkron programozással, szánjon egy percet a szinkron és az aszinkron viselkedés közötti különbség figyelembevételére. A szinkron metódus a munka befejezésekor ad vissza (5. lépés), de az aszinkron metódus a tevékenység értékét adja vissza a munka felfüggesztésekor (3. és 6. lépés). Amikor az aszinkron metódus végül befejezi a munkáját, a tevékenység befejezettként lesz megjelölve, és az eredmény (ha van ilyen) a tevékenységben van tárolva.

API aszinkron metódusok

Felmerülhet a kérdés, hogy hol talál olyan módszereket, mint az GetStringAsync aszinkron programozást támogató módszerek. .NET-keretrendszer 4.5-ös vagy újabb verzió, és a .NET Core számos olyan tagot tartalmaz, amelyek együttműködnek async és await. Ezeket a tagnévhez hozzáfűzött "Async" utótag, illetve a visszatérési Task típusuk vagy Task<TResult>a . Az osztály például olyan metódusokat tartalmaz, System.IO.Stream mint CopyToAsynca , ReadAsyncés WriteAsync a szinkron metódusok CopyTomellett , Readés Write.

A Windows-futtatókörnyezet számos olyan metódust is tartalmaz, amelyekkel windowsos alkalmazásokat asyncawait használhat. További információ: Szálkezelés és aszinkron programozás UWP-fejlesztéshez, aszinkron programozás (Windows Áruházbeli alkalmazások) és rövid útmutató: Aszinkron API-k meghívása C# vagy Visual Basic nyelven, ha a Windows-futtatókörnyezet korábbi verzióit használja.

Szálak

Az aszinkron metódusok nem blokkoló műveletek. Az await aszinkron metódusban lévő kifejezések nem tiltják le az aktuális szálat, amíg a várt feladat fut. Ehelyett a kifejezés folytatásként regisztrálja a metódus többi részét, és visszaadja a vezérlést az aszinkron metódus hívójának.

A async kulcsszavak és await a kulcsszavak nem okoznak további szálakat. Az aszinkron metódusok nem igényelnek többszálas műveletet, mert egy aszinkron metódus nem fut a saját szálán. A metódus az aktuális szinkronizálási környezetben fut, és csak akkor használ időt a szálon, ha a metódus aktív. A processzorhoz kötött munka háttérszálba való áthelyezésére használható Task.Run , de a háttérszálak nem segítenek olyan folyamatokban, amelyek csak arra várnak, hogy az eredmények elérhetővé váljanak.

Az aszinkron programozás aszinkron megközelítése szinte minden esetben előnyösebb a meglévő megközelítésekhez. Ez a megközelítés különösen jobb, mint az BackgroundWorker I/O-kötött műveletek osztálya, mivel a kód egyszerűbb, és nem kell védened a versenyfeltételeket. A metódussal kombinálva az Task.Run aszinkron programozás jobb, mint BackgroundWorker a cpu-kötött műveletek esetében, mivel az aszinkron programozás elválasztja a kód futtatásának koordinációs részleteit a szálkészletbe átviendő munkától Task.Run .

aszinkron és várakozási

Ha az aszinkron módosító használatával adja meg, hogy egy metódus aszinkron metódus, az alábbi két képességet engedélyezi.

  • A megjelölt aszinkron metódus használható a felfüggesztési pontok kijelölésére. Az await operátor tájékoztatja a fordítót, hogy az aszinkron metódus addig nem haladhat tovább, amíg a várt aszinkron folyamat be nem fejeződik. Addig is a vezérlő visszatér az aszinkron metódus hívójához.

    Az aszinkron metódus egy kifejezésnél await való felfüggesztése nem jelent kilépést a metódusból, és finally a blokkok nem futnak.

  • A megjelölt aszinkron metódust az azt meghívó metódusok is várhatják.

Az aszinkron metódus általában egy vagy több operátor előfordulását await tartalmazza, de a kifejezések hiánya await nem okoz fordítóhibát. Ha egy aszinkron metódus nem használ operátort await egy felfüggesztési pont megjelöléséhez, a metódus szinkron módon fut a módosító ellenére async . A fordító figyelmeztetést ad ki az ilyen módszerekre vonatkozóan.

async és await környezetfüggő kulcsszavak. További információkért és példákért tekintse meg a következő témaköröket:

Típusokat és paramétereket ad vissza

Az aszinkron metódus általában egy Task vagy egy Task<TResult>. Az aszinkron metóduson belül a rendszer egy operátort await alkalmaz egy másik aszinkron metódusra irányuló hívásból visszaadott feladatra.

Visszatérési típusként adja meg Task<TResult> , ha a metódus egy return operandus típusú TResultutasítást tartalmaz.

Akkor használja Task a visszatérési típust, ha a metódus nem tartalmaz visszatérési utasítást, vagy olyan visszatérési utasítással rendelkezik, amely nem ad vissza operandust.

Bármely más visszatérési típust is megadhat, feltéve, hogy a típus tartalmaz egy metódust GetAwaiter . ValueTask<TResult> egy ilyen típusra példa. A System.Threading.Tasks.Extension NuGet csomagban érhető el.

Az alábbi példa bemutatja, hogyan deklarálhat és hívhat meg egy metódust Task<TResult> , amely egy vagy több metódust Taskad vissza:

async Task<int> GetTaskOfTResultAsync()
{
    int hours = 0;
    await Task.Delay(0);

    return hours;
}


Task<int> returnedTaskTResult = GetTaskOfTResultAsync();
int intResult = await returnedTaskTResult;
// Single line
// int intResult = await GetTaskOfTResultAsync();

async Task GetTaskAsync()
{
    await Task.Delay(0);
    // No return statement needed
}

Task returnedTask = GetTaskAsync();
await returnedTask;
// Single line
await GetTaskAsync();

Minden visszaadott tevékenység a folyamatban lévő munkát jelöli. A tevékenységek információkat foglalnak össze az aszinkron folyamat állapotáról, és végül vagy a folyamat végeredményéről, vagy a folyamat által kiváltott kivételről, ha nem sikerül.

Az aszinkron metódusok visszatérési típussal void is rendelkezhetnek. Ez a visszatérési típus elsősorban eseménykezelők definiálására szolgál, ahol void visszatérési típusra van szükség. Az aszinkron eseménykezelők gyakran kiindulópontként szolgálnak az aszinkron programokhoz.

A visszatérési típussal rendelkező void aszinkron metódus nem várható meg, és a void-returning metódus hívója nem tudja elkapni a metódus által elvetett kivételeket.

Az aszinkron metódus nem tud paramétereket deklarálni, újrafésülni vagy kivenni, de a metódus meghívhatja az ilyen paraméterekkel rendelkező metódusokat. Hasonlóképpen, az aszinkron metódusok nem képesek hivatkozással visszaadni egy értéket, bár hiv visszatérési értékeket tartalmazó metódusokat is meghívhatnak.

További információkért és példákért lásd az Async visszatérési típusait (C#).

A Windows-futtatókörnyezet programozási aszinkron API-k a következő visszatérési típusok egyikével rendelkeznek, amelyek hasonlóak a feladatokhoz:

Elnevezési konvenció

Konvenció szerint a gyakran várt típusokat (például , Task, Task<T>, ValueTaskValueTask<T>) visszaadó metódusoknak "Async" végződésű névvel kell rendelkezniük. Az aszinkron műveletet indító, de nem várt típust visszaadó metódusoknak nem lehetnek "Async" végződésű neveik, de kezdődhetnek a "Start", a "Start" vagy más olyan igék, amelyek arra utalnak, hogy a metódus nem adja vissza vagy dobja el a művelet eredményét.

Figyelmen kívül hagyhatja azt a konvenciót, amelyben egy esemény, alaposztály vagy interfészszerződés más nevet javasol. Ne nevezze át például a gyakori eseménykezelőket, például OnButtonClick.

Kapcsolódó cikkek (Visual Studio)

Cím Leírás
Több webes kérés párhuzamos létrehozása aszinkron és várakozási (C#) használatával Bemutatja, hogyan indíthat egyszerre több feladatot.
Aszinkron visszatérési típusok (C#) Az aszinkron metódusok által visszaadható típusokat szemlélteti, és elmagyarázza, hogy az egyes típusok mikor megfelelőek.
A lemondási jogkivonattal rendelkező feladatok megszakítása jelzési mechanizmusként. A következő funkciók aszinkron megoldáshoz való hozzáadását mutatja be:

- Tevékenységek listájának törlése (C#)
- Tevékenységek megszakítása egy idő után (C#)
- Befejezett aszinkron feladat feldolgozása (C#)
Aszinkron használata fájlhozzáféréshez (C#) Felsorolja és bemutatja az aszinkron használat előnyeit, és várja a fájlok elérését.
Feladatalapú aszinkron minta (TAP) Aszinkron mintát ír le, a minta a típusokon és Task<TResult> a Task típusokon alapul.
Aszinkron videók a Channel 9-ben Az aszinkron programozásról szóló videókra mutató hivatkozások.

Lásd még