<address id="v5f1t"><meter id="v5f1t"><dfn id="v5f1t"></dfn></meter></address>

<nobr id="v5f1t"><i id="v5f1t"><em id="v5f1t"></em></i></nobr>
      <font id="v5f1t"></font>

    <font id="v5f1t"><ruby id="v5f1t"></ruby></font>

      <listing id="v5f1t"></listing>

        <dfn id="v5f1t"><ruby id="v5f1t"><form id="v5f1t"></form></ruby></dfn>

            <dfn id="v5f1t"></dfn>

            <progress id="v5f1t"><b id="v5f1t"><strike id="v5f1t"></strike></b></progress>

              <font id="v5f1t"></font>

                      微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      導讀多線程是指從軟件或者硬件實現多個線程并發執行的技術。具有多線程能力的計算機因有硬件支持而能夠在同一時間執行多于一個線程,進而提升整體處理性能。微軟混合現實技術專家賈里德

                      多線程(Multithreading)是指從軟件大概硬件實行多個線程并發實行的本領。具備多線程本領的計劃機因有硬件扶助而不妨在同偶爾間實行多于一個線程,從而提高完全處置本能。微軟攙和實際本領大師賈里德·拜恩茲(Jared Bienz)是一位馳名的軟件框架結構師,有著20多年的從業體味。日前,拜恩茲撰文瓜分了本人在AR/vr/MR多線程處置方面包車型的士八年體味和本領。底下是華夏AI網的簡直整治:

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      要精確實行多線程并遏制易,但它對于資源受限的挪動擺設流利運轉模仿至關要害。在服務于微軟的生存中,我偶爾機在四年多的功夫里扶助協調搭檔為HoloLens編寫高本能的運用步調。我其余有4年多的功夫扶助協調搭檔為智高手提式無線電話機寧靖板電腦編寫高本能運用步調。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      我早已蓄意撰寫這篇作品。這基礎上是我對AR/VR/MR模仿的多線程處置的8年體味瓜分。固然本文重要關心Unity和C#,但我蓄意個中引薦的觀念仍舊不妨為一切談話和平運動轉時的模仿開拓者帶來價格。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      1. 什么是線程?

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      我領會這是一個基礎性的題目,但我從它發端寫起是有一個要害因為。這個來由會在本章反面變得明顯起來。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      維基百科將線程刻畫為:不妨與其它指令并發實行的一系列指令。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      我夸大并發實行是由于它對這次計劃至關要害。并發運轉多個工作的本領使得線程對于模仿至關要害。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      2. 對于內核與線程的扼要證明

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      一個CPU不妨有多個內核,而有些內核不妨運轉多個線程。比方,Ryzen Threadripper最多有64個內核,每個內核不妨運轉2個線程。這表示著,即使你編寫的模仿屬于高度多線程,你大概會有多達128個不同的工作同時爆發。你不妨用這些線程來運轉NPC的人為智能大腦,大概在物理模仿中創造碰撞。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      但請記取,大學一年級致本質場景不會逼近128個線程。固然是英特爾的旗艦i9 10900k都不過供給20個并發線程。但是,編寫多線程代碼表示著供給多個內核的擺設不妨同時爆發多個工作。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      3. 線程何如感化運用步調

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      固然你不依附進步的人為智能,但簡直一切的MR運用都在某種程度上運用物理。比方,Hand Menu菜單中的按鈕會運用物理來檢驗和測定指尖何時交戰按鈕的表面。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      但遠比物理更要害的是襯托。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      簡直一切的玩耍引擎(包括Unity)都仍舊依附于單線程進行襯托。沒錯,惟有一個線程不妨在屏幕上繪制。固然是超底層的Directx API都只扶助在扶助線程上列隊吩咐。關系吩咐仍舊須要發送到襯托線程進行繪制。這是一個特其他線程。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      正如你不妨設想的那樣,從襯托線程獲得代碼不妨開釋引擎以繪制實質。你將博得更高的幀速度,看到更少的卡頓和頻閃。你的運用步調會發覺更加高響(高相應速率)和寧靜。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      4. 好吧,以是不要在Render Thread運轉代碼嗎?

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      這聽起來明顯像是在隱藏,不是嗎?但究竟表明,Render Thread是一切代碼運轉的默許場所。不只如許,在Render Thread運轉代碼是不行遏止的工作。為了證明因為,咱們底下來看看一個基礎的Unity立方體。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      使得立方體成為立方體的重要因為之一是稱為網格襯托器(Mesh Renderer)的動作。網格襯托器做什么?固然,它繪制立方體。換句話說,為了使一個Unity立方體成為一個立方體,它必需存在于Render Thread之上。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      Unity常常將Render Thread稱為干線程、運用線程、以及UI線程。請提防,它們都是同一個道理。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      5. coroutine(協程)與線程

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      當Unity開拓者創造coroutine時,大學一年級致人覺得他們仍舊創造了多線程。可惜的是,究竟遠非如許。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      Unity遏制一位coroutine的博士指出:coroutine就像一個函數,它不妨休憩實行并將遏制權返回給Unity,但而后會鄙人一個幀中貫穿實行。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      要害的是要認識到coroutine仍舊是在Render Thread上運轉。

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      設想一下一個大略的Unity運用步調在如許的輪回中運轉:

                       微軟MR技術專家分享:八年經驗和技能AR/VR多線程

                      即使動作A啟用兩個coroutine,則輪回將大略地變動為:

                      coroutine和正則函數的獨一辨別在于,coroutine的一限制不妨在幀之間掛起。掛起時會包括存在重要字yield的任何行。固然這大概會騰出功夫讓其余工作運轉,但編寫蹩腳的coroutine仍舊特出簡單給Render Thread形成宏大的負載。

                      coroutine特殊:你領會在coroutine展現特殊會爆發什么嗎?大概不是你設想的那樣。特殊不會遏止運用步調,以至不會禁止使用Behavior。獨一爆發的工作是,coroutine從革新輪回中unscheduled。Behavior不會提防到缺陷,以至不領會coroutine仍舊被unscheduled。

                      因為coroutine不是并發運轉,以是最佳把它看作是一個功夫切片機制。它們不是真實的多線程。

                      6. Thread.Start又何如?

                      咱們畢竟聊到多線程的第一個本質采用。System.Threading.Thread本質上代表一個線程,而調用Thread.Start將啟發工作在所述線程并發運轉。

                      但對于Thread類,你須要領會Thread類的實例表白一個不妨實行處事的東西,而不是乞求實行處事。很多函數不妨安置在Thread上運轉,而等候Thread實行并紛歧定表示著函數成功實行。比方,特殊大概會爆發。

                      恰是因為這些因為,通用Windows Platform(HoloLens運轉的平臺)以至不包括System.Threading.Thread。差異,UWP供給了一種名為ThreadPool的元素,個中各個處事變不妨進行scheduled。

                      在本文中,我不安排計劃Thread或ThreadPool,由于我蓄意中心計劃另一種本領。但是,我保持想大略地講講這些題目,由于來日運用Thread的Unity開拓者會因為代碼無法為HoloLens編寫翻譯感觸迷惑或懊喪。Thread類大概會被增添到UWP的將來版本中,但我蓄意表明固然它可用,咱們仍舊有更好的形式不妨按照。

                      7. 回調中的“貓膩”

                      什么是回調?維基百科將回調界說為:動作參數字傳送播給其余代碼的任何可實行代碼…這個實行…大概會在稍后的異步回調中爆發。

                      編寫“典范”多線程代碼的開拓者特出熟習回調,由于一旦你發端并發運轉代碼,不知何以你須要領會它是于何時實行。

                      底下是少許對于回調何如處事的偽代碼:

                      但即使代碼長久都沒有實行呢?即使由于文獻被鎖定或數據破壞而在第9行激勵特殊何如辦呢?

                      回調長久不會被調用。

                      即使沒有特出的編碼,運用步調將長久不會領會爆發了缺陷。就運用步調所知,LoadData已成功運轉。這是由于特殊沒有爆發在LoadData中,而是爆發在LoadData創造的線程中。

                      對于考查編寫和調節和測試多線程代碼的開拓者來說,不遏止(orphan)的回調從來是苦楚的基礎。簡而言之,這是由于乞求、處事和截止是實足辨別的。

                      回調與事變:請提防,回調形式偶爾不妨動作事變實行。Azure Spatial Anchors在探求錨點時會實行這一操縱。運用步調調用CreateWatcher發端探求,當找到錨及時,截止將經過AnchorLocated事變傳回。這偶爾會啟發預見不到的情景。比方,即使在功效器上廢除了錨定,則AnchorLocated事變將以NotLocateDanchordesNotExist的狀況觸發。其余,即使爆發搜集缺陷,運用步調不會領會,除非它同時訂閱了Error事變。我并不是說這是一個蹩腳的安排(見下文),但明顯,成功地運用鑒于事變的回調體例須要領會哪些情景會啟發哪些事變。

                      8. 什么是跨線程安排(scheduling)?

                      讓咱們再看看之前的偽代碼:

                      你提防到第12行對loadCompleted的調用本質上是在worker線程中實行的嗎?即使咱們想在數據加載后可視化,這會成為一個題目。請記取,loadCompleted是在worker線程上運轉的,但咱們只能在Render Thread創造GameObject。這就須要跨線程scheduling。

                      在Azure Spatial Anchors for Unity示例中,你不妨找到一個名為UnityDispatcher的腳本。UnityDispatcher承諾在任何線程上運轉的代碼乞求該代碼在Render Thread上運轉。你以至大概在沒蓄意識到的情景下看到了這一點。

                      以下是onCloudAnchorLocated handler的代碼片斷:

                      每當ASA定位到一個錨時,AnchorLocated事變將在worker線程上觸發。即使運用步調只需將動靜寫入日記,則不妨接收這個worker線程。究竟上這是更好的采用。但這個運用步調須要天生一個GameObject或挪動一個現有的GameObject,這兩個操縱只能在Render Thread上進行。InvokeOnAppThread表白“我領會我仍舊在一個worker線程,但我須要調用在Render Thread運轉的代碼”。

                      9. Unity的跨線程安排

                      固然一切多線程體例都有本人的scheduling辦法,但Unity的本擁有點不凡是。據我所知,Unity沒有供給直接的API來安排襯托線程上的處事。他們供給的是一種間接的辦法。

                      UnityDispatcher保持了須要在Render Thread上運轉的吩咐的列表。當一個worker線程調用InvokeOnAppThread時,這只會將代碼增添到列表中。當運用步調啟用時,UnityDispatcher將本人備案為coroutine。而后在每個幀上,UnityDispatcher查看列表中能否有任何實質。即使是如許,所述代碼將動作UnityDispatcher的Update例程的一限制實行。

                      UnityDispatcher沒有綁定到Azure空間錨,所以你不妨復制該類并在任何名目中運用它。即使沒有ASA,你也不妨從GitHub上的ThreadUtils名目中獲得這個類的副本。

                      10. Task-based Programming

                      針對C++開拓者的證明:我將要發端計劃Task-based Programming。我將引薦一個名為Task的C#,但你不會在C++ / WinRT中找到Task。差異,C++開拓者運用IasyccAct之類的接口,而當從C#調用時,這些接口會自動變換為Task。更多消息請參閱這邊。

                      如上所述,調節和測試多線程代碼特出艱巨,由于乞求、處事和截止都是彼此辨別的。但我向你承諾過一個更好的本領,我想此刻是功夫計劃它了。

                      很多開拓者都領會Task-based Programming,但很罕見人真實領會它在幕后的處事道理。Task-based Programming一致了咱們前方計劃過的觀念,大大減少了多線程代碼中墮落的機會。底下咱們來看看Task-based Programming是何如簡化線程、回融合跨線程scheduling。

                      11. Auto Threading

                      在C#中,每當一個函數被async重要字化裝時,咱們報告編寫翻譯器的是“這個代碼不妨在另一個線程上運轉”

                      讓咱們來看看將數據存在到文獻中的少許偽代碼:

                      在本例中,翻開文獻、寫入字節和封閉文獻都將在worker線程上實行。

                      這個神秘的worker線程是什么功夫創作出來的呢?它是在運用await操縱符時創造的。

                      即使咱們的示例運用步調具備以下代碼行:

                      這十分于:

                      異步函數中的代碼真實在新線程上運轉。但你的運用步調不須要領會這些細節,也不須要太多地關心。

                      更妙的是,正如斯蒂芬·圖布(Stephen Toub)常常說的:“等候的一個巧妙之處即是它能把你帶回從來的場合”。讓咱們看看這句話在另一個代碼示例中的含意吧:

                      咱們領會這段代碼是從Render Thread發端的,由于它是對按鈕點擊的相應。以是在第4行與GameObject交互是蓄意義的。但咱們同時領會,第7行的await重要字啟用了一個新線程。以是,何如本領與第10行和第11行的GameObjects交互呢?

                      答案是一個叫做SynchronizationContext的元素。簡而言之,不管何時運用await,編寫翻譯器城市記取在worker線程啟用之前有哪個線程正在運轉。編寫翻譯器同時會在worker線程實行后登時處置返回Starting Thread的操縱。是的,await自動處置跨線程scheduling。

                      要害提醒:await永不加塞。看起來像是await妨害了Starting Thread,但這不過編寫翻譯器的錯覺。await之前的一切實質都是內聯運轉,并且await之后的一切實質都由安排步調撥運輸轉。當Task在另一個線程中運轉時,Render Thread即是如許保護繪制的。

                      12. 跟蹤處事

                      正如我在Thread.Start一節指出地那樣:線程表白一個不妨實行處事的東西,而不是乞求實行處事。這是Task-based Programming的另一個亮點。任何Task實例本質上都表白一個要實行的處事的乞求。這恰是Task類具有IsCompleted和IsFaulted之類的屬性。

                      13. 數據與特殊

                      我在上頭提到回融合事變不妨在worker線程實行時返回數據。我同時提到了worker線程上的特殊常常表示著回調不運轉或事變不觸發。Task-based Programming經過將數據動作乞求本人的一限制來處置這個題目。

                      讓咱們來看看溝通的LoadData函數,但咱們將其動作Task而不是回調來實行:

                      讓咱們假如第7行實行少許數據反序列化。大學一年級致功夫,這十足都很好,但偶然咱們的運用步調會翻開一個破壞的文獻,第7行會議及展覽現一個特殊。請記取,這個特殊是在worker線程上激勵的。那么,Starting Thread何如處置這個特殊呢?比你設想的要大略:

                      當咱們等候一個Task而且該Task成功時,來自該Task的任何數據都將返回到Starting Thread。但是,即使咱們等候一個Task,而且在Task里面爆發了特殊,該特殊將傳遞回Starting Thread,就像它是內聯爆發一律。換句話說,在Task中處置特殊和在任何普遍函數中處置特殊都是一律的。

                      蓄意大師不妨發端領會為什么Task-based Programming會使多線程變得更簡單。Task-based Programming供給了一個簡單的一致模子。在這個模子中,乞求、處事和截止都真實地彼此關系。

                      14. 當廢除(Cancellation)特出要害的功夫

                      在某些情景下,Task大概會運轉很長功夫。比方,在慢速搜集左右載大文獻時。在這些場景中,使Task變得可廢除常常會很有扶助。不妨經過將CancellationToken傳播到異步函數來實行。而后,在運轉一會后,所述函數不妨在實行更多操縱之前查看Token能否已廢除。

                      底下是所述函數的大概格式:

                      盡大概一再地查看CancellationToken特出要害,如許不妨趕快廢除Task。調用ThrowIfCancellationRequested時,即使Token已被廢除,則所有Task以OperationCanceledException阻礙。

                      既然咱們仍舊看到Task不妨廢除,底下咱們來設想一下運用Task的Azure Spatial Anchors:

                      我并不是倡導ASA該當遏止運用事變而發端運用Task。ASA不妨同時探求多個錨,而ASA從不領會何時(以至能否)定位錨。事變在這種情景下的功效很好,只有你領會什么功夫觸發了哪些事變。但是,除了事變除外,增添對Task的扶助不妨扶助簡化很多罕見的場景。

                      15. coroutine保持有一席之地的

                      既然咱們仍舊領會Task的效率,有人民代表大會概會問為什么咱們要用其余辦法編寫代碼。但請記取,Task在worker線程上運轉,而GameObject只存在于Render Thread上。這即是coroutine的意旨地方。

                      coroutine在Render Thread上運轉,但不妨將功夫返回到襯托器。竅門是在yielding之前決定處事量。太少會須要很長功夫,而太多則會啟發運用步調沒有相應。

                      讓咱們設想一個不妨接受數據并用GameObject可視化的coroutine吧:

                      為了保護60 FPS,運用步調須要在大概16毫秒內襯托幀。咱們假如咱們的運用步調須要4毫秒來襯托。剩下的12毫秒不妨用來創造GameObject。

                      即使第10行須要2毫秒,咱們就會剩下6毫秒的容量。不只如許,咱們的運用步調每幀只能創造一個GameObject。

                      在本例中,更好的實行大概如下所示:

                      在C#中,%運算符計劃余數。以是這邊咱們說的是“每6個東西之后,把功夫還給襯托器。”6個東西x每個東西2毫秒=12毫秒(湊巧是咱們的估算)。

                      明顯,這個數字對于每個運用步調而言都是舉世無雙,而且會跟著功夫的推移而變革。運用步調大概會變得更加攙雜,須要更長的功夫來襯托。大概每個獨立的GameObject大概會變得更攙雜,須要更長的功夫來創造。沒有神秘的數字。要到達精確的平穩,你須要花功夫領略本能。

                      16. 將coroutine視作Task

                      以是coroutine有本人的蠻橫之地,但此刻咱們有兩種不同的本領來處置長功夫運轉的代碼。不只如許,除非咱們實行某種回調,否則運用步調將不領會VisualizeRoutine何時實行(咱們仍舊領會回調中的“貓膩”)。即使咱們能把coroutine看成Task來斡旋,那不是很好嗎?

                      有一個名為TaskCompletionSource的類承諾你將任何長功夫運轉的過程表白為一個Task。簡直如下:

                      在一個長功夫運轉的過程發端時,創造TaskCompletionSource。運用TaskCompletionSource.Task表白長功夫運轉的進程。實行后,運用TaskCompletionSource.SetResult返回數據。即使過程遇到缺陷,請運用TaskCompletionSource.SetException來傳遞特殊。咱們不妨很簡單地竄改VisualizationRoutine以接受TaskCompletionSource,并在實行后返回少許數據:

                      剩下的不過啟用coroutine并返回Task的helper函數:

                      17. coroutine中的特殊處置

                      即使你提防查看,你大概仍舊提防到上頭的coroutine中有一個特出要害的脫漏。即使在第26行之前爆發特殊會爆發什么工作呢?

                      可惜的是,coroutine不能供給與async溝通的編寫翻譯器功效。coroutine中沒有自動特殊傳遞,這表示著即使咱們不處置特殊,咱們將以爆發一個不遏止的Task。任多么待Task的代碼將長久不會回復。即使你覺得這聽起來很像是一個不遏止的回調,你一致精確。

                      你說:“沒題目。我把一切十足都打包到一個try/catch block中。”

                      大概看起來像如許:

                      這恰是你要做的工作,除了此刻第24行天生了一個CS1626編寫翻譯器缺陷。

                      缺陷CS1626無法在帶有catch clause的try block中天生值。

                      CS1626展現的因為特出攙雜,但你只需領會你不能將try/catch放在任何運用yield的行中。這給咱們留住了兩個大概的采用:

                      在任何非yield行范圍安置多個try/catch block。在IEnumerator范圍安置try/catch選項1最大略,但并非一切情景下都靈驗。比方,你不能將try/catch放在foreach語句范圍,由于foreach語句包括一個yield。

                      但咱們何如實行選項2?常常,IEnumerator直接傳播到startRoutine。

                      可惜的是,工作變得煩惱起來。IEnumerator接口有一個屬性和兩個函數。咱們必需保證,若任何part-IEnumerator爆發特殊,咱們就將阻礙Task。

                      為了扶助處置這個題目,我創造了ExceptionSafeRoutine。你不妨在GitHub的AsyncUtils.cs中找到它。ExceptionSafeRoutine接收一個IEnumerator和一個TaskCompletionSource。即使在IEnumerator中激勵任何特殊,則在TaskCompletionSource樹立該特殊。還有一個擴充本領不妨將任何IEnumerator變換為ExceptionSafeRoutine。

                      結果,咱們革新Visualization Async以保證Task一直實行:

                      這種本領的酷炫之處在于,任何特殊城市被傳遞。固然協程沒有try/catch block。這使得coroutine的處事辦法就像async一律。咱們獨一要記取的是,在發端一個coroutine時增添.WithExceptionHandling。

                      18. 歸納

                      即使你看到結果,蓄意你不妨向我瓜分你的辦法。你能否學到什么呢?有什么我須要填補大概脫漏的嗎?大概你有什么其余更好的計劃嗎?

                      免責聲明:本文章由會員“馬同”發布如果文章侵權,請聯系我們處理,本站僅提供信息存儲空間服務如因作品內容、版權和其他問題請于本站聯系
                      <address id="v5f1t"><meter id="v5f1t"><dfn id="v5f1t"></dfn></meter></address>

                      <nobr id="v5f1t"><i id="v5f1t"><em id="v5f1t"></em></i></nobr>
                          <font id="v5f1t"></font>

                        <font id="v5f1t"><ruby id="v5f1t"></ruby></font>

                          <listing id="v5f1t"></listing>

                            <dfn id="v5f1t"><ruby id="v5f1t"><form id="v5f1t"></form></ruby></dfn>

                                <dfn id="v5f1t"></dfn>

                                <progress id="v5f1t"><b id="v5f1t"><strike id="v5f1t"></strike></b></progress>

                                  <font id="v5f1t"></font>

                                          国产成人h片视频在线观看