Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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 aszinkron támogatást használ a .NET-futtatókörnyezetben. 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 cikk áttekintést nyújt az aszinkron programozás használatának időpontjáról és módjáról, valamint további részleteket és példákat tartalmazó cikkekre 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 és a Windows Futtatókörnyezetből származó felsorolt API-k 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-típusok aszinkron metódusokkal |
|---|---|---|
| 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-keretrendszerben, a .NET Core-ban vagy a Windows Futtatókörnyezetben található erőforrások segítségével 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.
A teljes Windows Presentation Foundation (WPF) példát letölthető formában megtalálhatja az "Aszinkron programozás aszinkronnal és várakozással C#-ban" című rész alatt.
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 így végződik Async. A metódus törzsében a GetStringAsync egy Task<string>-t ad vissza. Ez azt jelenti, hogy amikor await a feladatot, string-t kap (contents). Mielőtt elkezdené a feladatot, végezhet olyan munkát, amely nem függ a stringGetStringAsync-tól.
Figyeljen oda alaposan az await operátorra. Felfüggeszti a következőt GetUrlContentLengthAsync:
-
GetUrlContentLengthAsyncnem folytatható, amíggetStringTaskbe nem fejeződik. - Eközben az irányítás visszatér a hívóhoz
GetUrlContentLengthAsync. - A vezérlés itt folytatódik, amikor
getStringTaskbefejeződött. - Az
awaitoperátor ezután lekéri azstringeredménytgetStringTask-ből.
A visszatérési utasítás egy egész szám értéket 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
asyncmó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.
-
voidha aszinkron eseménykezelőt ír. - Bármely más típus, amely rendelkezik metódussal
GetAwaiter.
További információért lásd a Visszatérési típusok és paraméterek szakaszt.
-
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
awaitkifejezé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 cikk 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ában 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
GetUrlContentLengthAsyncmetódust.GetUrlContentLengthAsynclétrehoz egy HttpClient példányt, majd meghívja a GetStringAsync aszinkron metódust, hogy egy webhely tartalmát sztringként letöltse.Valami történik,
GetStringAsyncami 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ásokGetStringAsyncblokkolásának elkerülése érdekében átadja az irányítást a hívójának.GetUrlContentLengthAsyncGetStringAsyncvisszaad egy Task<TResult>, aholTResultegy sztring, ésGetUrlContentLengthAsynchozzárendeli a feladatot agetStringTaskváltozóhoz. A feladat a hívásGetStringAsyncfolyamatban 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
getStringTaskmég nem kerül várakozásra,GetUrlContentLengthAsyncfolytathatja azokat a munkákat, amelyek nem függnek aGetStringAsyncvégeredményétől. Ezt a munkát a szinkron metódusDoIndependentWorkhívása jelöli.DoIndependentWorkegy szinkron metódus, amely elvégzi a munkáját, és visszatér a hívóhoz.GetUrlContentLengthAsynckifogy azon munkákból, amelyeket agetStringTaskeredménye nélkül nem tud elvégezni.GetUrlContentLengthAsyncezutá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 az
GetUrlContentLengthAsyncawait operátort használja a folyamat felfüggesztésére, és a vezérlés átadására annak a metódusnak, amely aGetUrlContentLengthAsynchívást kezdeményezte.GetUrlContentLengthAsynca hívónak ad vissza egyTask<int>értéket. A feladat egy ígéretet jelent arra, hogy egy egész szám eredmény jön létre, amely megegyezik a letöltött karakterlánc hosszával.Megjegyzés
Ha
GetStringAsync(és ezértgetStringTask) befejeződik, mielőttGetUrlContentLengthAsyncmegvárná, az irányítás aGetUrlContentLengthAsync-ben marad. AzGetUrlContentLengthAsyncfelfüggesztésének és a visszatérés költsége elveszne, ha a hívott aszinkron folyamatgetStringTaskbefejeződött, ésGetUrlContentLengthAsyncnem kell várnia a végeredményre.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 módszer várakozikGetUrlContentLengthAsync-re, ésGetUrlContentLengthAsyncvárakozik aGetStringAsync-re.GetStringAsyncbefejezi és karakterlánc eredményt hoz létre. AGetStringAsynchívás nem a várt módon adja vissza a sztring eredményét. (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.getStringTaskA várakoztató operátor azgetStringTask-ból kéri le az eredményt. A hozzárendelési utasítás a lekért eredményt a következőhözcontentsrendeli: .Ha
GetUrlContentLengthAsynca sztring eredménye van, a metódus kiszámíthatja a sztring hosszát. Ezután a munkaGetUrlContentLengthAsyncis befejeződött, és a várakozó eseménykezelő újraindulhat. A cikk végén található teljes példában megerősítheti, hogy az eseménykezelő lekéri és kinyomtatja a hossz eredményének értékét. Ha még nem ismerkedik az aszinkron programozással, szánjon egy percet, hogy figyelembe vegye a szinkron és az aszinkron viselkedés közötti különbséget. 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. A .NET-keretrendszer 4.5-ös vagy újabb verziója és a .NET Core számos olyan tagot tartalmaz, amelyek async és await-vel dolgoznak. Ezeket az "Async" utótagról ismerheted fel, ami a tagnévhez van fűzve, és a Task vagy Task<TResult> visszatérési típusukról. Az System.IO.Stream osztály például olyan metódusokat tartalmaz, mint CopyToAsync, ReadAsync, és WriteAsync, valamint a szinkron metódusokat, mint CopyTo, Read, és Write.
A Windows Runtime számos olyan módszert is tartalmaz, amelyeket a async és a await elemekkel használhatunk a Windows-alkalmazásokban. 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 célja, hogy ne legyenek 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 és a await kulcsszavak nem okoznak extra szálak létrehozását. 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ás
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 tudja használni a await kifejezést, hogy megjelöljenek felfüggesztési pontokat. Az
awaitoperá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 felfüggesztése egy
awaitkifejezésnél nem jelenti a metódusból való kilépést, és afinallyblokkok nem futnak le.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ő cikkeket:
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 a Task<TResult>-t, ha a metódus tartalmaz egy return utasítást, amely egy TResult típusú operandust határoz meg.
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, ha 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, amely Task<TResult> vagy Task-t ad 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 folyamatban lévő munkát jelent. 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 deklarálhat in, ref vagy out paramétereket, de a metódus meghívhatja az ilyen paraméterekkel rendelkező metódusokat. Hasonlóképpen, az aszinkron metódusok nem képesek referenciaként visszaadni egy értéket, bár ref visszatérési értékekkel rendelkező 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örnyezeti programozás 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>, 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 szabad "Aszinkron" végződésű neveket használniuk, de kezdődhetnek a "Start", a "Start" vagy más olyan igével, amely arra utal, hogy a metódus nem adja vissza vagy nem 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. |
| Feladatok megszakítása megszakítási token használatával 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#) - Aszinkron feladatok feldolgozása, ahogy befejeződnek (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) | Az aszinkron mintát ismerteti. A minta a Task és Task<TResult> típusokon alapul. |
| Aszinkron videók a Channel 9-ben | Az aszinkron programozással kapcsolatos különböző videókra mutató hivatkozásokat tartalmaz. |