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.
Ez az oktatóanyag bemutatja, hogyan használhatja a Párhuzamos halmok ablak Feladatok nézetét egy C#-aszinkron alkalmazás hibakereséséhez. Ez az ablak segít megérteni és ellenőrizni az aszinkron/várakozási mintát (más néven feladatalapú aszinkron mintát (TAP) használó kód futásidejű viselkedését.
A párhuzamos feladattárat (TPL) használó, de az aszinkron/várakozási mintát nem használó alkalmazások, illetve az egyidejűségi futtatókörnyezetet használó C++ alkalmazások esetében a Párhuzamos verem ablakban a Szálak nézetet használhatja a hibakereséshez. További információ: Holtpont hibakeresése és Szálak és feladatok megtekintése a Párhuzamos verem ablakban.
A Feladatok nézet a következőkhöz nyújt segítséget:
Az aszinkron/várakozási mintát használó alkalmazások hívásveremvizualizációinak megtekintése. Ezekben a forgatókönyvekben a Feladatok nézet teljesebb képet nyújt az alkalmazás állapotáról.
Azonosítsa a futtatásra ütemezett, de még nem futó aszinkron kódot. Például egy olyan HTTP-kérés, amely nem adott vissza adatokat, valószínűbb, hogy a Szálak nézet helyett a Feladatok nézetben jelenik meg, ami segít elkülöníteni a problémát.
Segít azonosítani az olyan problémákat, mint a szinkronizálási aszinkron minta, valamint a lehetséges problémákra, például a blokkolt vagy várakozó feladatokra vonatkozó tippeket. A sync-over-async kódminta olyan kódra utal, amely szinkron módon hív aszinkron metódusokat. Ez ismert módon blokkolja a szálakat, és ez a szálkészlet éhezésének leggyakoribb oka.
Aszinkron hívásveremek
A Párhuzamos halmok Feladatok nézete vizualizációt biztosít az aszinkron hívásveremekhez, így láthatja, hogy mi történik (vagy kellene) az alkalmazásban.
Az alábbiakban néhány fontos szempontot érdemes megjegyezni, amikor a Feladatok nézetben értelmezi az adatokat.
Az aszinkron hívásveremek logikai vagy virtuális hívásveremek, nem pedig a vermet képviselő fizikai hívásveremek. Ha aszinkron kóddal dolgozik (például a
awaitkulcsszó használatával), a hibakereső megjeleníti az "aszinkron hívásveremek" vagy a "virtuális hívásveremek" nézetét. Az aszinkron hívásveremek eltérnek a szálalapú hívásveremektől vagy a "fizikai veremektől", mivel az aszinkron hívásveremek jelenleg nem feltétlenül futnak fizikai szálon. Ehelyett az aszinkron hívásveremek olyan kód folytatásai vagy "ígéretei", amelyek a jövőben aszinkron módon fognak futni. A hívásveremek folytatások használatával jönnek létre.Az ütemezett, de jelenleg nem futó aszinkron kód nem jelenik meg a fizikai hívásveremen, de a Feladatok nézetben az aszinkron hívásveremen kell megjelennie. Ha olyan metódusokkal blokkolja a szálakat, mint a
.Waitvagy.Result, akkor a kód a fizikai hívásveremben jelenhet meg.Az aszinkron virtuális hívásveremek nem mindig intuitívak, mivel az elágazás olyan metódushívások használatából ered, mint például
.WaitAnyvagy.WaitAll.A Hívásverem ablak a Feladatok nézettel kombinálva hasznos lehet, mivel az aktuális végrehajtási szálhoz tartozó fizikai hívásverem látható.
A virtuális hívásverem azonos szakaszai csoportosítva vannak az összetett alkalmazások vizualizációjának egyszerűsítése érdekében.
Az alábbi fogalmi animáció bemutatja, hogyan alkalmazzák a virtuális hívási veremeken a csoportosítást. Csak a virtuális hívásverem azonos szegmensei vannak csoportosítva. Vigye az egérmutatót egy csoportosított hívásveremre, hogy azonosítsa a feladatokat futtató szálakat.
C#-minta
Az útmutató mintakódja egy olyan alkalmazáshoz készült, amely egy gorilla életének egy napját szimulálja. A gyakorlat célja annak megismerése, hogyan használható a Párhuzamos halmok ablak Feladatok nézete egy aszinkron alkalmazás hibakereséséhez.
A minta egy példát tartalmaz a sync-over-async mintázat hibás alkalmazásának bemutatására, ami a szálkészlet kimerüléséhez vezethet.
A hívásverem intuitívsá tétele érdekében a mintaalkalmazás a következő szekvenciális lépéseket hajtja végre:
- Létrehoz egy gorillát jelképező objektumot.
- Gorilla felébred.
- Gorilla megy egy reggeli sétára.
- Gorilla banánt talál a dzsungelben.
- Gorilla eszik.
- A gorilla bohóckodik.
A mintaprojekt létrehozása
Nyissa meg a Visual Studiót, és hozzon létre egy új projektet.
Ha a kezdőablak nincs megnyitva, válassza Fájl>Ablak indításalehetőséget.
A kezdőablakban válassza az Új projekt lehetőséget.
Az Új projekt létrehozása ablakban írja be vagy írja be a keresőmezőbe a konzolt . Ezután válassza C# a Nyelv listából, majd válassza Windows a Platform listából.
A nyelv- és platformszűrők alkalmazása után válassza a .NET konzolalkalmazást , majd a Tovább gombot.
Megjegyzés:
Ha nem látja a megfelelő sablont, lépjen az Eszközök>lekérése eszközök és szolgáltatások lapra, amely megnyitja a Visual Studio Installert. Válassza a .NET asztali fejlesztés munka terhelését, majd válassza a Módosítás lehetőséget.
Az új projekt konfigurálása ablakban írjon be egy nevet, vagy használja az alapértelmezett nevet a Projektnév mezőbe. Ezután válassza a Következőlehetőséget.
.NET esetén válassza az ajánlott cél keretrendszert vagy a .NET 8-at, majd válassza a Létrehozás lehetőséget.
Megjelenik egy új konzolprojekt. A projekt létrehozása után megjelenik egy forrásfájl.
Nyissa meg a .cs kódfájlt a projektben. Üres kódfájl létrehozásához törölje annak tartalmát.
Illessze be a választott nyelvhez tartozó alábbi kódot az üres kódfájlba.
using System.Diagnostics; namespace AsyncTasks_SyncOverAsync { class Jungle { public static async Task<int> FindBananas() { await Task.Delay(1000); Console.WriteLine("Got bananas."); return 0; } static async Task Gorilla_Start() { Debugger.Break(); Gorilla koko = new Gorilla(); int result = await Task.Run(koko.WakeUp); } static async Task Main(string[] args) { List<Task> tasks = new List<Task>(); for (int i = 0; i < 2; i++) { Task task = Gorilla_Start(); tasks.Add(task); } await Task.WhenAll(tasks); } } class Gorilla { public async Task<int> WakeUp() { int myResult = await MorningWalk(); return myResult; } public async Task<int> MorningWalk() { int myResult = await Jungle.FindBananas(); GobbleUpBananas(myResult); return myResult; } /// <summary> /// Calls a .Wait. /// </summary> public void GobbleUpBananas(int food) { Console.WriteLine("Trying to gobble up food synchronously..."); Task mb = DoSomeMonkeyBusiness(); mb.Wait(); } public async Task DoSomeMonkeyBusiness() { Debugger.Break(); while (!System.Diagnostics.Debugger.IsAttached) { Thread.Sleep(100); } await Task.Delay(30000); Console.WriteLine("Monkey business done"); } } }A kódfájl frissítése után mentse a módosításokat, és hozza létre a megoldást.
A Fájl menüben válassza az Összes mentése lehetőséget.
A Build menüben válassza a Megoldás összeállításalehetőséget.
A Párhuzamos halmok ablak Feladatok nézetének használata
A Hibakeresés menüben válassza a Hibakeresés indítása (vagy F5) lehetőséget, és várja meg az első
Debugger.Break()találatot.Nyomja le egyszer az F5 billentyűt, és a hibakereső ismét megáll ugyanazon
Debugger.Break()a sorban.Ez szünetel a második hívásban
Gorilla_Start, amely egy második aszinkron feladaton belül történik.A Párhuzamos halmok ablak megnyitásához válassza a Windows > párhuzamos halmok hibakeresése > lehetőséget, majd az ablak Nézet legördülő listájában válassza a Feladatok lehetőséget.
Figyelje meg, hogy az aszinkron hívásverem címkéi 2 aszinkron logikai vermet írnak le. Amikor legutóbb lenyomta az F5 billentyűt, egy másik feladatot indított el. Az összetett alkalmazások egyszerűsítése érdekében az azonos aszinkron hívásveremek egyetlen vizuális ábrázolásba vannak csoportosítva. Ez teljesebb információkat nyújt, különösen a sok feladatot tartalmazó forgatókönyvekben.
A Feladatok nézettel ellentétben a Hívásverem ablak csak az aktuális szál hívásveremét jeleníti meg, több tevékenység esetén nem. Gyakran hasznos, ha mindkettőt együtt tekinti meg, hogy teljesebb képet adjon az alkalmazás állapotáról.
Jótanács
A Hívásverem ablak megjelenítheti az olyan információkat, mint például a holtpont, a leírás
Async cyclealapján.A hibakeresés során beállíthatja, hogy megjelenjen-e külső kód. A funkció váltásához kattintson a jobb gombbal a Hívásverem ablak Névtábla fejlécére, majd válassza a Külső kód megjelenítése lehetőséget, vagy törölje a jelölését. Ha külső kódot jelenít meg, akkor is használhatja ezt az útmutatót, de az eredmények eltérhetnek az ábráktól.
Nyomja le ismét az F5 billentyűt, és a hibakereső szünetelteti a
DoSomeMonkeyBusinessmetódust.
Ez a nézet teljesebb aszinkron hívásvermet mutat, miután több aszinkron metódust hozzáadtak a belső folytatási láncolathoz, ami az olyan metódusok használatakor fordul elő, mint a
await.DoSomeMonkeyBusinesslehet, hogy jelen van vagy nincs az aszinkron hívásverem tetején, mivel egy aszinkron metódusról van szó, amely még nincs hozzáadva a végrehajtási lánchoz. A következő lépésekben megvizsgáljuk, hogy miért ez a helyzet.Ebben a nézetben a
Jungle.Mainletiltott ikonja
is látható. Ez informatív, de általában nem jelez problémát. A blokkolt tevékenység azért van letiltva, mert egy másik tevékenységre vár, egy jelzésre váró eseményre vagy egy feloldandó zárolásra.Vigye az egérmutatót a
GobbleUpBananasmetódusra, hogy információkat kapjon a feladatokat futtató két szálról.
Az aktuális szál a Hibakeresés eszköztár Szál listájában is megjelenik.
A szál lista használatával a hibakereső környezetet egy másik szálra válthatja.
Nyomja le ismét az F5 billentyűt, és a hibakereső szünetelteti a
DoSomeMonkeyBusinessmásodik feladat metódusát.
A feladat végrehajtásának időzítésétől függően ezen a ponton különálló vagy csoportosított aszinkron hívásveremek jelennek meg.
Az előző ábrán a két tevékenység aszinkron hívásveremei külön-külön vannak, mert nem azonosak.
Nyomja le ismét az F5 billentyűt, és hosszú késés jelenik meg, és a Feladatok nézet nem jelenít meg aszinkron hívásveremadatokat.
A késést egy hosszan futó feladat okozza. Ebben a példában egy hosszú ideig futó feladatot szimulál, például egy webes kérést, amely a szálkészlet éhezését eredményezheti. A Feladatok nézetben semmi sem jelenik meg, mert bár a feladatok le lehetnek tiltva, Ön jelenleg nincs szüneteltetve a hibakeresőben.
Jótanács
Az Összes megszakítás gomb jó módszer a hívásverem információinak lekérésére, ha holtpont áll fenn, vagy az összes tevékenység és szál jelenleg le van tiltva.
A hibakeresési eszköztár IDE tetején válassza az Összes megszakítása gombot (szüneteltetés ikon), Ctrl+ Alt+ Break.
A Feladatok nézetben az aszinkron hívásverem tetején látható, hogy
GobbleUpBananasez le van tiltva. Valójában két tevékenység blokkolva van ugyanazon a ponton. A blokkolt tevékenység nem feltétlenül váratlan, és nem feltétlenül jelenti azt, hogy probléma merült fel. A végrehajtás megfigyelt késése azonban problémát jelez, és az itt található hívásverem-információk a probléma helyét mutatják.Az előző képernyőkép bal oldalán a görbült zöld nyíl jelzi az aktuális hibakereső környezetet. A két feladat blokkolva van
mb.Wait()aGobbleUpBananasmetódusban.A Hívásverem ablak azt is megjeleníti, hogy az aktuális szál blokkolva van.
A
Wait()hívása letiltja a szálakat aGobbleUpBananas-hez való szinkron híváson belül. Ez egy példa a sync-over-async antipatternre, és ha ez egy felhasználói felületen vagy nagy feldolgozási munkaterhelés alatt történt, akkor általában egy kódjavítással,awaitoldják meg a problémát. További információért lásd: A szálkészlet kimerülésének hibakeresése. Ha profilkészítési eszközöket használ a szálkészlet éhezésének hibakeresésére, tekintse meg az Esettanulmány: Teljesítményproblémák elkülönítése részt.Szintén érdekes,
DoSomeMonkeyBusinessnem jelenik meg a hívási veremben. Jelenleg ütemezett, nem fut, ezért csak az aszinkron hívásveremben jelenik meg a Feladatok nézetben.Jótanács
A hibakereső szálonként törik át a kódot. Ez azt jelenti például, hogy ha az F5 billentyűt lenyomva folytatja a végrehajtást, és az alkalmazás eléri a következő töréspontot, az egy másik szálon lévő kódra törhet. Ha hibakeresési célból kell kezelnie ezt a funkciót, hozzáadhat további töréspontokat, hozzáadhat feltételes töréspontokat, vagy használhatja az Összes megszakítást. További információ erről a viselkedésről: Egyetlen szál követése feltételes töréspontokkal.
A mintakód javítása
Cserélje le a metódust
GobbleUpBananasa következő kódra.public async Task GobbleUpBananas(int food) // Previously returned void. { Console.WriteLine("Trying to gobble up food..."); //Task mb = DoSomeMonkeyBusiness(); //mb.Wait(); await DoSomeMonkeyBusiness(); }A metódusban a GobbleUpBananas függvényt hívja meg
MorningWalkhasználatávalawait.await GobbleUpBananas(myResult);Válassza az Újraindítás gombot (Ctrl + Shift + F5), majd nyomja le többször az F5 billentyűt, amíg az alkalmazás le nem áll.
Nyomja meg a 'Mindent megszakít' gombot.
Ezúttal
GobbleUpBananasaszinkron módon fut. Ha megszakad, megjelenik az aszinkron hívásverem.
A Hívásverem ablak üres, kivéve a bejegyzést
ExternalCode.A kódszerkesztő nem jelenít meg semmit, csak azt jelzi, hogy az összes szál külső kódot hajt végre.
A Feladatok nézet azonban hasznos információkat nyújt.
DoSomeMonkeyBusinessa várt módon az aszinkron hívásverem tetején található. Ez helyesen jelzi, hogy hol található a hosszú futású metódus. Ez hasznos az aszinkron/várakozási problémák elkülönítéséhez, ha a Hívásverem ablakban lévő fizikai hívásverem nem nyújt elegendő adatot.
Összefoglalás
Ez az útmutató a Párhuzamos verem hibakereső ablakát mutatta be. Használja ezt az ablakot az aszinkron/várakozási mintát használó alkalmazásokban.