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 GetStringAsync
Task<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íggetStringTask
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 astring
következőbőlgetStringTask
: .
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
TResult
szerepel. - 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.
- Task<TResult> ha a metódus olyan visszatérési utasítással rendelkezik, amelyben az operandus típusa
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:
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.
A hívó metódus meghívja és várja az aszinkron
GetUrlContentLengthAsync
metódust.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.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ásokGetStringAsync
blokkolásának elkerülése érdekében szabályozza a hívót.GetUrlContentLengthAsync
GetStringAsync
visszaad egy Task<TResult>, aholTResult
egy sztring, ésGetUrlContentLengthAsync
hozzárendeli a feladatot agetStringTask
változóhoz. A feladat a hívásGetStringAsync
folyamatban 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.Mivel
getStringTask
még nem várták meg, folytathatja azokat a munkát,GetUrlContentLengthAsync
amelyek nem függnek a végeredménytőlGetStringAsync
. Ezt a munkát a szinkron metódusDoIndependentWork
hívása jelöli.DoIndependentWork
egy szinkron metódus, amely elvégzi a munkáját, és visszatér a hívóhoz.GetUrlContentLengthAsync
elfogyott 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ívottGetUrlContentLengthAsync
metódushoz való hozzáférés szabályozására.GetUrlContentLengthAsync
a hívónak ad vissza egyTask<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értgetStringTask
) befejeződik, mielőttGetUrlContentLengthAsync
megvárja, az irányítás a következőbenGetUrlContentLengthAsync
marad: . Ha az úgynevezett aszinkron folyamatgetStringTask
már befejeződöttGetUrlContentLengthAsync
, és nem kell várnia a végeredményre, a felfüggesztés, majd a visszatérésGetUrlContentLengthAsync
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árakozikGetUrlContentLengthAsync
, ésGetUrlContentLengthAsync
a következőreGetStringAsync
vár.GetStringAsync
befejezi és sztringeredményt hoz létre. A sztring eredményét a hívásGetStringAsync
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őlgetStringTask
kéri le az eredményt: . A hozzárendelési utasítás a lekért eredményt a következőhözcontents
rendeli: .Ha
GetUrlContentLengthAsync
a sztring eredménye van, a metódus kiszámíthatja a sztring hosszát. Ezután a munkaGetUrlContentLengthAsync
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 async
await
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, ésfinally
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ú TResult
utasí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:
- IAsyncOperation<TResult>, amely megfelel a Task<TResult>
- IAsyncAction, amely megfelel a Task
- IAsyncActionWithProgress<TProgress>
- IAsyncOperationWithProgress<TResult,TProgress>
Elnevezési konvenció
Konvenció szerint a gyakran várt típusokat (például , Task
, Task<T>
, ValueTask
ValueTask<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. |