Тази статия е огледална статия за машинен превод, моля, кликнете тук, за да преминете към оригиналната статия.

Изглед: 6277|Отговор: 2

[Комуникация] [Завърти се] Изречение. Задача. Резултатът ще бъде заключен, как иначе да напиша този код?

[Копирай линк]
Публикувано на 2022-8-7 21:11:58 | | | |
1: Предистория

1. Разказвай истории

Преди няколко дни, когато индексирах статията за .NET Advanced Debugging в github, намерих интересен коментар, вижте статията за подробности, скрийншотът е следният:



Вероятно означава, че изпълнението на Task.Result под основната тема на Winform ще доведе до задънена улица, също разгледах линка към референцията на снимката, Стивън е абсолютният шеф, но тази статия е основно за индоктринацията на голям параграф текст и не ти позволява да видиш това, което виждаш, затова ще я анализирам от гледна точка на windbg.

2: Анализ на Windbg

1. Ще бъде ли наистина блокиран?

Разбира се, не съм играл Winform от много години и не мога да разбера дали ще играе, поне не на конзолата.

Кодът е много прост – стартирай програмата, щракне-клик и, разбира се, интерфейсът е заседнал, което е малко невероятно.

2. Търсете причината за задънената улица

След това, побързайте и прикрепете вятърния инструмент към процеса, за да разберете.

1) Погледнете основната тема
Интерфейсът не реагира, така че естествено основната нишка е заседнала, така че трябва да провериш какво прави основната нишка в момента. Използвайте командата ~0s + !clrstack.

0:000> !clrstack
OS Thread ID: 0x5a10 (0)
        Child SP IP Call Site
0000004d10dfde00 00007ffb889a10e4 [GCFrame: 0000004d10dfde00]
0000004d10dfdf28 00007ffb889a10e4 [HelperMethodFrame_1OBJ: 0000004d10dfdf28] System.threading.Monitor.ObjWait(boolean, int32, system.object)
0000004d10dfe040 00007ffb66920d64 System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)
0000004d10dfe0d0 00007ffb6691b4bb System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)
0000004d10dfe140 00007ffb672601d1 System.Threading.Tasks.Task.InternalWait(Int32, System.Threading.CancellationToken)
0000004d10dfe210 00007ffb6725cfa7 System.Threading.Tasks.Task'1[[System.__Canon, mscorlib]]. GetResultCore (Boolean)
000004d10dfe250 00007ffb18172a1b WindowsFormsApp4.Form1.button1_Click(System.Object, System.EventArgs) [E:\net5\ConsoleApp1\WindowsFormsApp4\Form1.cs @ 26]
0000004d10dfe2b0 00007ffb3a024747 System.Windows.Forms.Control.OnClick(System.EventArgs)
000004d10dfe2f0 00007ffb3a027b83 System.Windows.Forms.Button.OnClick(System.EventArgs)
0000004d10dfe340 00007ffb3a837231 System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)
000004d10dfe400 00007ffb3a7e097d System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message byRef, System.Windows.Forms.MouseButtons, int32)
000004d10dfe480 00007ffb3a0311cc System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message byRef)
0000004d10dfe540 00007ffb3a0b0c97 System.Windows.Forms.ButtonBase.WndProc(System.Windows.Forms.Message byRef)
0000004d10dfe5c0 00007ffb3a0b0be5 System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message byRef)
000004d10dfe5f0 00007ffb3a030082 System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
000004d10dfe690 00007ffb3a765a02 DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int64, Int32, Int64, Int64)
000004d10dfe9d0 00007ffb776d221e [InlinedCallFrame: 0000004d10dfe9d0] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0000004d10dfe9d0 00007ffb3a0b9489 [InlinedCallFrame: 0000004d10dfe9d0] System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0000004d10dfe9a0 00007ffb3a0b9489 DomainBoundILStubClass.IL_STUB_PInvoke(MSG ByRef)
0000004d10dfea60 00007ffb3a046661 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop( IntPtr, Int32, Int32)
0000004d10dfeb50 00007ffb3a045fc7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0000004d10dfebf0 00007ffb3a045dc2 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
000004d10dfec50 00007ffb181708e2 WindowsFormsApp4.Program.Main() [E:\net5\ConsoleApp1\WindowsFormsApp4\Program.cs @ 19]
0000004d10dfee78 00007ffb776d6923 [GCFrame: 0000004d10dfee78]
От изхода на стека основната нишка най-накрая е заседнала на Monitor.ObjWait под Task.Result, което означава, че все още не е изтеглена последния jsonString, което е много странно, минали са няколко минути, има ли проблем с мрежата? Мрежата ми е 100 метра пълна с огнева мощ...

2) Къде отиде jsonString?
Ако jsonString се намери в управляваната купчина, това означава, че има нещо в програмата, което прави закъснението на резултата, използвайте командата !dumpheap -type String -min 8500 + !do 000001f19002fcf0 за преглед, както е показано на фигурата по-долу:



От фигурата ясно се вижда, че html се е върнал, тъй като всичко е върнато, защо Task.Result все още не е приключил? Следващата стъпка е да се види кой държи този html и да се използва !gcroot.

0:000> !gcroot 000001f19002fcf0
Тема 5a10:
    000004d10dfe250 00007ffb18172a1b WindowsFormsApp4.Form1.button1_Click(System.Object, System.EventArgs) [E:\net5\ConsoleApp1\WindowsFormsApp4\Form1.cs @ 26]
        RBP+10: 0000004d10dfe2b0
            -> 000001f180007f78 WindowsFormsApp4.Form1
            -> 000001f180070d68 System.ComponentModel.EventHandlelerList
            -> 000001f180071718 System.ComponentModel.EventHandlelerList+ListEntry
            -> 000001f1800716d8 System.EventHandler
            -> 000001f1800716b0 System.Windows.Forms.ApplicationContext
            -> 000001f180071780 System.EventHandler
            -> 000001f18006ab38 System.Windows.Forms.Application+ThreadContext
            -> 000001f18006b140 System.Windows.Forms.Application+MarshalingControl
            -> 000001f18016c9c8 System.Collections.Queue
            -> 000001f18016ca00 Система. Обект[]
            -> 000001f18016c948 System.Windows.Forms.Control+ThreadMethodEntry
            -> 000001f18016c8b8 Система. Обект[]
            -> 000001f1800e6f80 Система. Действие
            -> 000001f1800e6f60 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner
            -> 000001f1800a77d0 WindowsFormsApp4.Form1+<GetJsonAsync>d__2
            -> 000001f1800b4e50 System.Threading.Tasks.Task'1[[System.String, mscorlib]]
            -> 000001f19002fcf0 System.String

Открих 1 уникален корен (бягай! GCRoot -all', за да се видят всички корени).
От резултатите от изходите този System.String най-накрая се съхранява от WindowsFormsApp4.Form1 на нишката 5a10 и можеш да използваш !t, за да провериш коя нишка е 5a10.

0:000> !t заключване  
       ID OSID нишкаOBJ състояние GC режим GC Alloc Контекстен домейн брой на пригодни изключения
   0 1 5a10 000001f1f1f1b01200 2026020 Преемптивен 000001F1800E70E8:000001F1800E7FD0 000001f1f1ad5b90 0 STA
   2 2 712c 000001f1f1b2a270 2b220 Преемптивен 00000000000000000000000000000000000000 000000001f1f1ad5b90 0 MTA (Финализатор)
Отидох, 5a10 се оказа основната нишка, беше доста объркващо, основната нишка беше заседнала, а конецът беше държан от основния конец, напълно необяснимо.

3) Търсете пробивни точки
Все още се връщам и спокойно размишлявам върху тази референтна верига, открих, че тук има опашка: -> 000001f18016c9c8 System.Collections.Queue, имам идея, мога да дебъгвам изходния код, като поставя точка на прекъсване в опашката и инструментът използва DnSpy, просто го направи.



Както се вижда от фигурата, при влизане в Queue се използва нишка 10, което означава, че низът все още не е държан от основната нишка в момента.



От диаграмата се вижда, че непрекъснатата задача най-накрая се планира от WindowsFormsSynchronizationContext.Post в опашката под контрол, а данните в тази опашка трябва да се изпълняват от UI нишката, така че има следния диалог:

Основна тема: Задача, братко, кога ще го изпълниш? Чакам да завършиш сигнала?

задача:Братко, ако не ме екзекутираш, как ще го завърша?

Основна тема:О...

В обобщение: задачата за продължение е достигнала опашката, чакаща основната нишка да се изпълни, и в този момент основната нишка е зашеметена и чака задачата за продължение да завърши=true, проблемът е тук: как задачата за продължение не може да се изпълни Complete=true? Така че са такива.

Трето: Как да го разгадаем

Като знаем причинно-следствената връзка, този метод на напукване е прост, грубо разделен на два вида.

1. Забранено е да се пуска задача за продължение в опашка

За да се прекъсне този път, импликацията е да се остави пулът на нишките да завърши задачата сам, така че UI нишката да усети, че задачата е изпълнена, и накрая да получи финалния html, който означава да добави ConfigureAwait(false) след await, както следва:



2. Блокирайте основната нишка

Ако основната нишка не е блокирана, тогава тя може свободно да получи задачите, които трябва да се изпълнят в Control.Queue, а методът е много прост – просто добави waitit преди GetJsonAsync.



Трето: Резюме

Заключението е да правиш повече собствена практическа практика, теоретичните знания ти се внушават насилствено от другите, независимо дали са правилни или грешни, всъщност нямаш дъно в сърцето си, практическото потвърждение е това, което наистина ти принадлежи, и е трудно да забравиш, все пак наистина си преживял, практикувал и проверил.

Оригинален:Входът към хиперлинк е видим.





Предишен:Docker модифицира и ограничава контейнерния процесор, памет и други ресурси
Следващ:JS масивите са разликата и предназначението на всеки и някои
Публикувано на 2022-8-8 17:01:32 |
Научи се да учиш...
Публикувано на 2022-9-2 11:39:19 |
Научи малко
Отричане:
Целият софтуер, програмни материали или статии, публикувани от Code Farmer Network, са само за учебни и изследователски цели; Горното съдържание не трябва да се използва за търговски или незаконни цели, в противен случай потребителите ще понесат всички последствия. Информацията на този сайт идва от интернет, а споровете за авторски права нямат нищо общо с този сайт. Трябва напълно да изтриете горното съдържание от компютъра си в рамките на 24 часа след изтеглянето. Ако ви харесва програмата, моля, подкрепете оригинален софтуер, купете регистрация и получете по-добри услуги. Ако има нарушение, моля, свържете се с нас по имейл.

Mail To:help@itsvse.com