http://blog.csdn.net/hany3000/article/details/16917571
如果你想在游戲中使用多線程,你應該看看這篇文章,線程是一個相當復雜的話題,但如果你掌握了它,你就可以從容的使用多個硬件處理器或處理很難划分管理數據塊.
如在場景中用A*算法進行大量的數據計算.
變形網格中操作大量的頂點.
持續的要運行上傳數據到服務器.
二維碼識別等圖像處理.
如果同時你要處理很多事情或者與Unity的對象互動小可以用thread,否則使用coroutine.
線程是在你程序中與其他線程同時運行的進行.在多處理器的計算機上可以做到多個線程的真正的同步.更多的線程取決於有多個處理核心.
Unity編程時,總有個主線程執行你的代碼,也可以創建額外的線程和主線程同時運行.
而Unity中,你僅能從主線程中訪問Unity的組件,對象和Unity系統調用.任何企圖訪問這些項目的第二個線程都將失敗並引發錯誤.這是一個要重視的一個限制.
所以當你寫代碼時,你認為一個函數開始並達到它執行的點后返回,同樣你做的東西又在另外一個函數中執行,但又沒有發生相應的變化.操作系統決定你代碼的執行,任何時候,你的代碼只能暫時”休眠”掉,然后讓另外的代碼開始運行,

在這個例子中,在第一個線程將A的值加載到CPU寄存器中准備+1后被中斷,第二個線程來讀取A的值,並減去1000,這時A應該是-950.現在第一個線程重新開始,它在寄存器中的50+1的結果存儲於A,A變成了51,而-950已經丟掉了.
從根本上說,要在用多個線程在同時對變量或內存訪問時,要采取很多預防措施來確保不會發生這樣的事.
所以Unity決定從另外線程訪問這些變量或者內存是無效的,只是為了避免所有系統和框架對象出現問題.
所以要確保一次只有一個線程來修改變量,這不意味着你不能用多線程工作,你可以用”排序”來解決這個問題.
C#中有lock這個關鍵字,以確保只有一個線程可以在特定時間內訪問特定的對象.這里說對象是因為無法鎖定一個類型值(value type)或原型(primitive).
object guard = new object();
void ThreadOneCode()
{
//一些代碼在這
lock(guard)
{
a = a + 1;
}
//其余一些代碼在這
}
void ThreadTwoCode()
{
//一些代碼在這
lock(guard)
{
a = a - 1000;
}
現在你可能會有各種各樣的問題,比如你要鎖定的不止一件事,可能是互相嵌套的.那我們該怎么辦呢?
我們這個類叫Loom,讓你可以輕松在另一個線程運行代碼,
這里有兩個要注意的功能:
RunAsync(Action)-在另一個線程上運行的一組代碼.
QueueOnMainThread(Action,[可選]float time)-運行在主線程的語句(可選延遲).
用Loom.Current訪問Loom-創建一個看不見的GameObject用來處理游戲主線程的互動.
下面這個例子用Loom來更新一個網格所有的頂點乘的結果.
<code "=""> //運行一個Action在新的線程
Loom.RunAsync(()=>{
//遍歷所有的頂點
for(var i = 0; i < vertices.Length; i++)
{
//縮放頂點
vertices[i] = vertices[i] * scale;
}
//在主線程上運行一些代碼
//更新網格
Loom.QueueOnMainThread(()=>{
//設置頂點
mesh.vertices = vertices;
//重新計算邊界
mesh.RecalculateBounds();
});
上面這個是個很好的例子,使用lambda函數在第二個線程上做一個沒有參數,不需要返回任何內容的操作. closures都是在你自己的類和函數的參數和局部變量的訪問.
你可以用 ()=>{ … } 定義一個lambda函數來在新的線程上運行函數內所有的代碼.
在主線程上我們需要將修改的網格頂點更新,所以我們使用QueueOnMainThread在接下來的時間更新周期運行處理(此幀或下一幀被稱為接下來的更新周期). QueueOnMainThread也需要一個Action來將更新的頂點更新到原來的網格.
如果是UnityScript,你可以這樣使用Loom:
<code "=""> //運行一個Action在新的線程
Loom.RunAsync(function() {
//遍歷所有的頂點
for(var i = 0; i < vertices.Length; i++)
{
//縮放頂點
vertices[i] = vertices[i] * scale;
}
//在主線程上運行一些代碼
//更新網格
Loom.QueueOnMainThread(function() {
//設置頂點
mesh.vertices = vertices;
//重新計算邊界
mesh.RecalculateBounds();
});
