免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
游戲引擎Unity中的單線程與多線程

因?yàn)楣ぷ鞯脑?,第一次接觸到Unity3D游戲引擎,開拓了眼界,學(xué)到不少新知識。

今天與大家聊一聊我覺得在Unity3D中最基礎(chǔ)也是最重要的概念:Unity3D的單線程與多線程。

最近項(xiàng)目中,有一個(gè)網(wǎng)絡(luò)操作的小需求,我按照其他移動端的研發(fā)經(jīng)驗(yàn),使用Unity的網(wǎng)絡(luò)庫UnityEngine.WWW或者UnityEngine.Networking,然后new Thread放入子線程運(yùn)行網(wǎng)絡(luò),結(jié)果非常尷尬的遇到了can only be called from the main thread.的異常,百思不得其解。


為什么不能在子線程中操作UnityEngine SDK?


我?guī)е@個(gè)疑問,開始了探索。發(fā)現(xiàn)如下規(guī)律:

1. UnityEngine的API與對象都不能在子線程中運(yùn)行

2. UnityEngine定義的基本結(jié)構(gòu)(int,float,Struct定義的數(shù)據(jù)類型)可以在子線程中運(yùn)行。例如Vector3(Struct)可以,但Texture2d對象則不可以,因?yàn)槠涓割悶閁nityEngine.Object)。


概括起來,Unity3D中的子線程無法運(yùn)行Unity SDK API。

其實(shí),當(dāng)Unity對其SDK做了這個(gè)限制之后,我們可以非??隙ǖ恼fUnity是單線程的游戲引擎。

為什么要做這個(gè)限制?因?yàn)?/span>游戲中邏輯更新和畫面更新的時(shí)間點(diǎn)要求有確定性,必須按照幀序列嚴(yán)格保持同步,否則就會出現(xiàn)游戲中的對象不同步的現(xiàn)象。多線程也能保證這個(gè)效果,但如果引入多線程,會加大同步處理的難度與游戲的不穩(wěn)定性。腦補(bǔ)一下這張圖中的場景,如果卡頓了是什么感受:-)


明白了Unity3D是單線程設(shè)計(jì)之后,我繼續(xù)帶著疑問探索。


Unity3D的線程運(yùn)行機(jī)制是怎樣的呢?


最近寫了一點(diǎn)游戲腳本,一般都要求繼承MonoBehavior對象,會在OnStart()中做地圖初始化,在OnUpdate()中進(jìn)行幀刷新,然后MonoBehavior腳本可以作為一個(gè)Component掛載到某個(gè)GameObject中。

這一點(diǎn)點(diǎn)入門級的理解大致能在游戲中把地圖引擎跑起來,但是并沒有深入的去理解這些框架函數(shù)的執(zhí)行原理。

先上一張Unity3D運(yùn)行機(jī)制的圖: 


初看起來可能不太理解,但是隨著項(xiàng)目深入,相信會逐步理解其中的含義。 

第一次學(xué)**Unity3D,我認(rèn)為可以簡單一點(diǎn)理解:這是一個(gè)單線程的幀循環(huán),每一次繪制都會重新走一遍生命周期。 

展開來說,主要包含以下部分: 

1. 初始化。對于常用的OnStart()框架方法只會被調(diào)用一次。 

2. 物理。比如游戲中的碰撞處理。 

3. 事件輸入。例如手勢 

4. Update(), 協(xié)程(Coroutine),LastUpdate() 

5. 渲染Rendering。包含常用的OnPreRender(), onPostRender() 

6. 銷毀。 

詳細(xì)的理解可以查看官方文檔:http://docs.unity3d.com/Manual/ExecutionOrder.html (點(diǎn)擊『閱讀原文』)

掌握這張圖的精髓或許是理解Unity3D的關(guān)鍵,需要時(shí)間沉淀。目前我所掌握的有:

OnPreRender: 在相機(jī)開始渲染場景之前調(diào)用此函數(shù)。

OnPostRender: 在相機(jī)完成場景渲染后調(diào)用此函數(shù)。

Update: 在每幀上調(diào)用一次 Update() 函數(shù)。

Unity3D中協(xié)程(Coroutine)究竟是什么?

介紹完了Unity3D的生命周期,來說說協(xié)程(Coroutine)。

協(xié)程是什么呢?總體來說,對與Unity,它是單線程的設(shè)計(jì),它更傾向使用time slicing(時(shí)間分片)的協(xié)程(coroutine)去完成異步任務(wù),融合到了剛剛提到的生命周期中。

要理解協(xié)程,先回顧下線程:線程是操作系統(tǒng)級別的概念,現(xiàn)代操作系統(tǒng)都實(shí)現(xiàn)并且支持線程,線程的調(diào)度對應(yīng)用開發(fā)者是透明的,開發(fā)者無法預(yù)期某線程在何時(shí)被調(diào)度執(zhí)行。基于此,一般那種隨機(jī)出現(xiàn)的BUG,多與線程調(diào)度相關(guān)。

而協(xié)程Coroutine是編譯器級的,本質(zhì)還是一個(gè)線程時(shí)間分片去執(zhí)行代碼段。它通過**相關(guān)的代碼使得代碼段能夠?qū)崿F(xiàn)分段式的執(zhí)行,顯式調(diào)用yield函數(shù)后才被掛起,重新開始的地方是yield關(guān)鍵字指定的,一次一定會跑到一個(gè)yield對應(yīng)的地方。因?yàn)閰f(xié)程本質(zhì)上還是在主線程里執(zhí)行的,需要內(nèi)部有一個(gè)類似棧的數(shù)據(jù)結(jié)構(gòu),當(dāng)該coroutine被掛起時(shí)要保存該coroutine的數(shù)據(jù)現(xiàn)場以便恢復(fù)執(zhí)行。

在Unity3D中,協(xié)程是可自行停止運(yùn)行 (yield),直到給定的 YieldInstruction 結(jié)束再繼續(xù)運(yùn)行的函數(shù)。 協(xié)程 (Coroutines) 的不同用途:

· yield; 在下一幀上調(diào)用所有 Update 函數(shù)后,協(xié)同程序?qū)⒗^續(xù)運(yùn)行。

· yield WaitForSeconds(2); 在指定的時(shí)間延遲之后,為此幀調(diào)用所有 Update 函數(shù)之后繼續(xù)運(yùn)行

· yield WaitForFixedUpdate(); 在所有腳本上調(diào)用所有 FixedUpdate 后繼續(xù)運(yùn)行

· yield WWW 完成 WWW 下載后繼續(xù)運(yùn)行。

· yield StartCoroutine(MyFunc); 連接協(xié)同程序,并等待 MyFunc coroutine 首先結(jié)束。

也就是說,將代碼段分散在不同的幀中,每次執(zhí)行一段,下一幀再執(zhí)行yield掛起的地方。

舉個(gè)例子: 在OnStart()框架函數(shù)中調(diào)用startCoroutine(GetHttpData)執(zhí)行以下代碼端,其實(shí)是第一次發(fā)起網(wǎng)絡(luò)請求,下一次執(zhí)行時(shí)則走入yield之后的代碼段繼續(xù)執(zhí)行,從而實(shí)現(xiàn)了一個(gè)時(shí)間分片的”異步”效果,而不是像線程那樣在操作系統(tǒng)層面分CPU時(shí)間片去執(zhí)行。 

    IEnumerator GetHttpData(string str) {
        UnityWebRequest www = UnityWebRequest.Get(str);
        yield return www.Send();

        if(www.isError) {
            Debug.Log(www.error);
        }
        else {
            // Show results as text
            Debug.Log("Downloaded " + str);

            // Or retrieve results as binary data
            byte[] results = www.downloadHandler.data;
            
        }
    }

Unity中無法使用子線程了嗎?

先回顧下前面提到的內(nèi)容:

(1) Unity是單線程設(shè)計(jì)的游戲引擎,子線程中無法運(yùn)行Unity SDK 

(2) Unity主循環(huán)是單線程,游戲腳本MonoBehavior有著嚴(yán)格的生命周期

(3) 傾向使用time slicing(時(shí)間分片)的協(xié)程(coroutine)去完成異步任務(wù)

這三點(diǎn)是Unity3D最為基礎(chǔ)也是最為重要的概念,熟練掌握才算入門了Unity3D開發(fā)。

但這些并不意味著無法在Unity中使用多線程,只是需要注意使用的場景。

試想一下,如果在幀序列的主循環(huán)單線程中處理大量耗時(shí)操作,勢必會帶來游戲畫面的卡頓,幀率的下降。

因此,對于不是畫面更新,也不是常規(guī)的邏輯更新(指包括AI、物理碰撞、角色控制這些),而是一些其他后臺任務(wù),則可以將這個(gè)獨(dú)立出來開辟一個(gè)子線程。

所以,在不使用Unity SDK的前提下,確保做好主子線程的同步(采用C#中的delegate等機(jī)制),那么是可以合理使用子線程的。 

概括起來,結(jié)合過往移動端的研發(fā)經(jīng)驗(yàn),我認(rèn)為有以下幾點(diǎn)可以在子線程中處理: 

(1) 大量耗時(shí)的數(shù)據(jù)計(jì)算

(2) 網(wǎng)絡(luò)請求 

(3) 復(fù)雜密集的I/O操作

(4) Unity3D的NativePlugin中可以新建子線程。通過NativePlugin可以接入移動端iOS與Android中的成熟庫,可以是Objective C, Java, C++三種語言交叉混合的方式組成NativePlugin,然后使用Android或者iOS的SDK開辟子線程。 

(這也是Unity3D中比較關(guān)鍵的技術(shù),后續(xù)有空單獨(dú)開篇談?wù)勎业睦斫狻#?nbsp;

關(guān)于這個(gè)話題,先聊到這里,或許遇到新問題又會有更為深入的發(fā)現(xiàn)。 


本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
協(xié)程到底有什么用?6種I/O模式告訴你!
Unity3D中協(xié)程Coroutine&yield
MonoBehaviour類Invoke, Coroutine
關(guān)于Unity3D的協(xié)程(Coroutine)
Unity多線程(Thread)和主線程(MainThread)交互使用類
Unity面試題(含答案)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服