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 Visual Studio 2012 egyszerűsített megközelítést, aszinkron programozást vezetett be, amely a .NET-keretrendszer 4.5-ös és újabb verzióiban, valamint a Windows futtatókörnyezetben is aszinkron támogatást nyújt. 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 nélkülözhetetlen az olyan tevékenységekhez, amelyek blokkolva lehetnek, például amikor az alkalmazás hozzáfér az internethez. A webes erőforrásokhoz való hozzáférés néha lassú vagy késleltetett. Ha egy ilyen tevékenység szinkronizálási folyamaton belül le van tiltva, 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-keretrendszer 4.5-ös és Windows-futtatókörnyezetében felsorolt API-k olyan metódusokat tartalmaznak, amelyek támogatják az aszinkron programozást.
Alkalmazásterület | Az aszinkron metódusokat tartalmazó támogató API-k |
---|---|
Webes hozzáférés | HttpClient, SyndicationClient |
Fájlok használata | StorageFile, StreamWriter, StreamReaderXmlReader |
Képek használata | \ |
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 írása egyszerűbb
Az Async és a Await kulcsszavak a Visual Basicben az aszinkron programozás alapjai. A két kulcsszó használatával a .NET-keretrendszerben 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. Azokat az aszinkron metódusokat, amelyeket Async
és Await
használatával definiál, aszinkron metódusoknak nevezzük.
Az alábbi példa egy aszinkron metódust mutat be. A kód szinte minden elemének teljesen ismerősnek kell lennie. A megjegyzések kiemelik az aszinkronizálás létrehozásához hozzáadott funkciókat.
A témakör végén egy teljes Windows Presentation Foundation (WPF) példafájl található, és letöltheti a mintát az Aszinkron Példa: Példa az "Aszinkron programozás 'async' és 'await' használatával" című cikkből.
' Three things to note about writing an Async Function:
' - The function has an Async modifier.
' - Its return type is Task or Task(Of T). (See "Return Types" section.)
' - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
Using client As New HttpClient()
' Call and await separately.
' - AccessTheWebAsync can do other things while GetStringAsync is also running.
' - getStringTask stores the task we get from the call to GetStringAsync.
' - Task(Of String) means it is a task which returns a String when it is done.
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com/dotnet")
' You can do other work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork()
' The Await operator suspends AccessTheWebAsync.
' - AccessTheWebAsync does not continue until getStringTask is complete.
' - Meanwhile, control returns to the caller of AccessTheWebAsync.
' - Control resumes here when getStringTask is complete.
' - The Await operator then retrieves the String result from getStringTask.
Dim urlContents As String = Await getStringTask
' The Return statement specifies an Integer result.
' A method which awaits AccessTheWebAsync receives the Length value.
Return urlContents.Length
End Using
End Function
Ha AccessTheWebAsync
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.
Dim urlContents As String = Await client.GetStringAsync()
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(Of TResult), ha a metódus olyan visszatérési utasítással rendelkezik, amelyben az operandus TResult típusú.
- 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.
- Feliratkozás, ha aszinkron eseménykezelőt írsz.
További információt a jelen témakör későbbi, "Visszatérési típusok és paraméterek" című szakaszában talál.
A metódus általában tartalmaz legalább egy várakozási 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 aszinkron működésről további információt a TPL és a hagyományos .NET-keretrendszer aszinkron programozása című témakörben talál.
Mi történik az Async-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:
Egy eseménykezelő meghívja és várja az aszinkron
AccessTheWebAsync
metódust.AccessTheWebAsync
lé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,
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 átadja az irányítást a hívójának.AccessTheWebAsync
GetStringAsync
Visszaad egy Task(Of TResult)-t, ahol a TResult egy karaktersorozat, ésAccessTheWebAsync
hozzárendeli a Taskot 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,AccessTheWebAsync
folytathatja azokat a munkákat, 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.AccessTheWebAsync
kifogyott a munkából, amit végezhetnegetStringTask
eredménye nélkül.AccessTheWebAsync
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 az
AccessTheWebAsync
await operátort használja a folyamat felfüggesztésére, és a vezérlés átadására annak a metódusnak, amely aAccessTheWebAsync
hívást kezdeményezte.AccessTheWebAsync
a hívónak ad vissza egyTask(Of Integer)
é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ődött, mielőttAccessTheWebAsync
azt várná, az irányításAccessTheWebAsync
marad. Ha az úgynevezett aszinkron folyamat (AccessTheWebAsync
) már befejeződött, és az AccessTheWebSyncnek nem kell megvárnia a végeredményt, a felfüggesztés, majd a visszatérésgetStringTask
költsége elveszne.A hívóban (ebben a példában az eseménykezelőben) 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
AccessTheWebAsync
, mielőtt az eredményre várna, vagy a hívó azonnal várakozhat. Az eseménykezelő a következőreAccessTheWebAsync
vár, ésAccessTheWebAsync
a következőreGetStringAsync
vár:GetStringAsync
befejezi és karakterlánc eredményt hoz létre. AGetStringAsync
hí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.getStringTask
A 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özurlContents
rendeli: .Ha
AccessTheWebAsync
a sztring eredménye van, a metódus kiszámíthatja a sztring hosszát. Ezután a munkaAccessTheWebAsync
is befejeződött, és a várakozó eseménykezelő újraindulhat. A témakör végén található teljes példában ellenőrizheti, hogy az eseménykezelő lekéri és kinyomtatja az eredmény hosszának é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.
A vezérlési folyamatról további információt az Async-programok (Visual Basic) vezérlőfolyamatai című témakörben talál.
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 számos olyan tagot tartalmaz, amelyek a Async
-val és a Await
-vel együtt dolgoznak. Ezeket a tagokat az "Async" utótaggal ismerheti fel, amely a tag nevéhez csatlakozik, valamint Task vagy Task(Of TResult) visszatérési típussal rendelkezik. 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ókért és példákért lásd: Aszinkron API-k meghívása C# vagy Visual Basic nyelven, Aszinkron programozás (Windows Futtatókörnyezeti alkalmazások) és WhenAny: Áthidalás a .NET-keretrendszer és a Windows-futtatókörnyezet között.
Témák
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 Await
kulcsszavak nem okoznak további 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 előnyös az I/O-kötött műveleteknél, mivel a kód egyszerűbb, és nem kell a versenyhelyzetekkel foglalkozni. Az aszinkron programozás Task.Run kombinálva jobb a processzorhoz kötött műveleteknél, mint BackgroundWorker, mivel az aszinkron programozás elválasztja a kód futtatásának koordinációs részleteit a munkától, amelyet a Task.Run
átad a szálkészletnek.
Async és Await
Ha Aszinkron módosító használatával adja meg, hogy egy metódus aszinkron metódus, akkor az alábbi két funkciót kell engedélyeznie.
A megjelölt aszinkron metódus a Await használatával kijelölheti a felfüggesztési pontokat. Az await operátor tájékoztatja a fordítót, hogy az aszinkron metódus nem folytatódhat azon a ponton túl, 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
Await
kifejezésnél nem jelenti a metódusból való kilépést, és aFinally
blokkok 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ő témaköröket:
Típusokat és paramétereket ad vissza
A .NET-keretrendszer programozásában az aszinkron metódus általában egy Task vagy egy (TResult) típusú feladatot ad vissza. 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.
A Task(Of TResult) értéket adja meg visszatérési típusként, ha a metódus olyan Return utasítást tartalmaz, amely egy operandus típusú TResult
értéket ad 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.
Az alábbi példa bemutatja, hogyan deklarálhat és hívhat meg egy metódust, amely visszaad egy Task(Of TResult)-t vagy egy Task:
' Signature specifies Task(Of Integer)
Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)
Dim hours As Integer
' . . .
' Return statement specifies an integer result.
Return hours
End Function
' Calls to TaskOfTResult_MethodAsync
Dim returnedTaskTResult As Task(Of Integer) = TaskOfTResult_MethodAsync()
Dim intResult As Integer = Await returnedTaskTResult
' or, in a single statement
Dim intResult As Integer = Await TaskOfTResult_MethodAsync()
' Signature specifies Task
Async Function Task_MethodAsync() As Task
' . . .
' The method has no return statement.
End Function
' Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync()
Await returnedTask
' or, in a single statement
Await Task_MethodAsync()
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ódus is lehet Sub
metódus. Ez a visszatérési típus elsősorban eseménykezelők definiálására szolgál, ahol visszatérési típusra van szükség. Az aszinkron eseménykezelők gyakran kiindulópontként szolgálnak az aszinkron programokhoz.
Az eljárásnak Sub
minősülő aszinkron metódus nem várható meg, és a hívó nem tudja elkapni a metódus által elvetett kivételeket.
Az aszinkron metódus nem deklarálhat ByRef-paramétereket , de a metódus meghívhatja az ilyen paraméterekkel rendelkező metódusokat.
További információkért és példákért lásd: Async Return Types (Visual Basic). Aszinkron metódusokban a kivételek kezeléséről részletesen lásd: Try...Catch...Finally Statement.
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(Of TResult), amely a Task(Of TResult) függvénynek felel meg
- IAsyncAction, amely megfelel a Task
- IAsyncActionWithProgress(Of TProgress)
- IAsyncOperationWithProgress(Of TResult, TProgress)
További információ és példa: Aszinkron API-k meghívása C# vagy Visual Basic nyelven.
Elnevezési konvenció
Konvenció szerint hozzáfűzi az "Async" kifejezést a módosítóval rendelkező Async
metódusok nevéhez.
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 Button1_Click
.
Kapcsolódó témakörök és minták (Visual Studio)
Teljes példa
Az alábbi kód a jelen témakör által tárgyalt Windows Presentation Foundation (WPF) alkalmazás MainWindow.xaml.vb fájlja. A mintát az Async-mintából töltheti le: Példa az "Aszinkron programozás az Async és a Await használatával" című cikkből.
Imports System.Net.Http
' Example that demonstrates Asynchronous Programming with Async and Await.
' It uses HttpClient.GetStringAsync to download the contents of a website.
' Sample Output:
' Working . . . . . . .
'
' Length of the downloaded string: 39678.
Class MainWindow
' Mark the event handler with Async so you can use Await in it.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' Call and await immediately.
' StartButton_Click suspends until AccessTheWebAsync is done.
Dim contentLength As Integer = Await AccessTheWebAsync()
ResultsTextBox.Text &= $"{vbCrLf}Length of the downloaded string: {contentLength}.{vbCrLf}"
End Sub
' Three things to note about writing an Async Function:
' - The function has an Async modifier.
' - Its return type is Task or Task(Of T). (See "Return Types" section.)
' - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
Using client As New HttpClient()
' Call and await separately.
' - AccessTheWebAsync can do other things while GetStringAsync is also running.
' - getStringTask stores the task we get from the call to GetStringAsync.
' - Task(Of String) means it is a task which returns a String when it is done.
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com/dotnet")
' You can do other work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork()
' The Await operator suspends AccessTheWebAsync.
' - AccessTheWebAsync does not continue until getStringTask is complete.
' - Meanwhile, control returns to the caller of AccessTheWebAsync.
' - Control resumes here when getStringTask is complete.
' - The Await operator then retrieves the String result from getStringTask.
Dim urlContents As String = Await getStringTask
' The Return statement specifies an Integer result.
' A method which awaits AccessTheWebAsync receives the Length value.
Return urlContents.Length
End Using
End Function
Sub DoIndependentWork()
ResultsTextBox.Text &= $"Working . . . . . . .{vbCrLf}"
End Sub
End Class