2016-07-22 23 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 ..

相关问题