2016-07-22 20 views
0

我在Unity3D中爲iOS和Android構建面部檢測應用程序。該應用程序應該檢測每秒10張臉。但是,每個人臉檢測需要大約50ms,所以我決定讓人臉檢測在另一個線程的後臺運行,以防止出現小的滯後尖峯(應用程序需要每幀更新視覺材料,50ms停止使它laggy)。線程化導致應用程序在iOS上滯後,但不在Android上

問題是線程導致應用程序在iOS上滯後。沒有線程,它用於檢測每秒10個面,現在有2個線程。它在Android上工作正常。

有什麼不可思議的是是該應用程序在iOS上運行良好的前5秒。不管它是否檢測到臉部,5秒後都會出現嚴重滯後。編輯:如果我暫停應用程序,然後恢復它滯後5秒鐘消失像在開始。這是什麼!?

下面是一個協同處理臉部檢測的例子,它每秒運行10次。如果面部檢測線程在100毫秒內未完成,則會阻止另一個線程啓動。

IEnumerator FaceDetection() 
    { 
     while (true) 
     { 
      if (faceDetectionThreadDone) 
      { 
       rgbaMat = webCamTextureToMatHelper.GetMat(); 
       if (rgbaMat != null) 
       { 
        OpenCVForUnityUtils.SetImage(faceLandmarkDetector, rgbaMat); 
        faceDetectionThreadDone = false; 

        new Thread(() => 
        { 
         Thread.CurrentThread.IsBackground = true; 

         // heavy computing stuff (50 ms) 
         List<UnityEngine.Rect> detectResult = faceLandmarkDetector.Detect(); 
         if (detectResult.Count > 0) 
         { 
          points = faceLandmarkDetector.DetectLandmark(detectResult[0]); 

         } 
         faceDetectionThreadDone = true; 
        }).Start(); 

       } 
      } 
      yield return new WaitForSeconds(0.1f); 
     } 
    } 

是否有一些嚴重的問題,我如何創建新的線程?我讀過一些地方,他們完成執行後會被垃圾收集器清理乾淨。可能會造成滯後?編譯設置設置爲高性能等。

編輯:好吧,我很確定現在問題是不涉及內存管理。我已經在Xcode中運行了內部剖析器,並觀察了堆的使用情況。演出]沒有得到受影響時,垃圾收集踢

,我測試的應用程序上的設備:iPhone 6,索尼Z3,三星S4

+1

有你檢查了iOS和Android的構建設置。我認爲可以啓用多線程功能。 – MyIsaak

+0

是的,我已經看過,並嘗試各種構建設置。雖然沒有找到任何特定的多線程。 – Johan

+0

你檢查我的答案了嗎? – Programmer

回答

2

創建和啓動Thread是昂貴的。每次調用

Thread(() => 
{ 
//Code 
}).Start(); 

被調用時,大約分配了1 MB內存。添加其中發生的其他內存分配,例如List(detectResult)創建。

此外,yield return new WaitForSeconds(0.1f);分配內存,但我不認爲這是問題。你可以通過在while循環之前聲明WaitForSeconds然後使用它來防止這種情況。

例如,

//Create instance of WaitForSeconds once, before the while loop 
WaitForSeconds waitForSeconds = new WaitForSeconds(0.1f); 

while (true){ 
//your Thread code 
} 
yield return waitForSeconds; //No more memory allocation 

真的不認爲這是主要的問題,但我把那個讓你知道你能做到這一點。對於上面提到的Thread問題,您應該創建一個處理數據的while循環,然後在主Thread中執行輸出。基本上是一個線程函數,將永遠循環,而不是每次創建一個新的Thread

有一個名爲Unity Threading Helper的插件,允許您從另一個線程調用Unity API函數。你可能想要使用它。它有付費和免費版本。免費版本中不包含示例。這是唯一的區別,但你可以在我發佈的鏈接上下載它和它的例子。

下面是如何使用該API的一般示例。閱讀代碼中的評論。你的工作是將你的問題中的代碼放入適當的位置,這很容易做到。

bool keepProcessing; 
UnityThreading.ActionThread myThread; 
void Start() 
{ 
    keepProcessing = true; 
    //Create Thread once 
    myThread = UnityThreadHelper.CreateThread(() => 
    { 
     //Will process Data forever! 
     while (keepProcessing) 
     { 
      //Do heavy computing stuff 

      //Computing Done! Do something with the output data 
      UnityThreadHelper.Dispatcher.Dispatch(() => 
       { 
        //You can safely call Unity API functions inside this codeblock 
       } 

      //Wait so that Unity won't Freeze 
      Thread.Sleep(1); 
     } 
    }); 
} 

void stopProcessing() 
{ 
    keepProcessing = false; 
    myThread.Abort(); 
} 

最後,我建議你重新設計你的DetectLandmark功能採取array作爲參數,而不是List。分配足夠的陣列內存一次然後重新使用它。這將徹底刪除您的應用程序的內存分配。

+0

是的,只創建一個線程好得多,謝謝。但它並沒有解決我的問題。 5秒後線程中的大量計算內容仍然會變慢。表演真的下降了,眨眼之間從完美到可怕。我開始認爲它不是一個線程相關的問題,但是當我在主線程中使用大量計算的東西時,性能沒有下降,這一事實不斷告訴我,問題可能在於facelandmarkDetector對象如何獲取當應用程序爲iOS構建時從第二個線程訪問。 – Johan

+0

@Johan我真的不知道你的'faceLandmarkDetector.Detect()'和'faceLandmarkDetector.DetectLandmark'函數看起來像什麼,但它們實際上可能是問題所在。 – Programmer

0

在1/30幀和60幀29/30設置Application.targetFrameRate 15解決它......

必須是一個團結VSYNC相關的bug ..

相關問題