C# 线程导致应用程序在iOS上延迟,但在Android上没有

C# 线程导致应用程序在iOS上延迟,但在Android上没有,c#,ios,multithreading,opencv,unity3d,C#,Ios,Multithreading,Opencv,Unity3d,我正在为iOS和Android构建Unity3D人脸检测应用程序。该应用程序应该每秒检测10张脸。但是,每次人脸检测大约需要50毫秒,因此我决定让人脸检测在另一个线程的后台运行,以防止出现小的延迟峰值(应用程序需要每帧更新一次视觉内容,50毫秒的停止会使其延迟) 问题是线程导致应用程序在iOS上滞后。不穿线时,它用于每秒检测10个面,现在穿线时检测2个面。。它在Android上运行良好 奇怪的是,该应用程序在iOS上的前5秒运行良好。不管它是否检测到人脸,5秒后会出现严重的延迟。编辑:如果我暂停

我正在为iOS和Android构建Unity3D人脸检测应用程序。该应用程序应该每秒检测10张脸。但是,每次人脸检测大约需要50毫秒,因此我决定让人脸检测在另一个线程的后台运行,以防止出现小的延迟峰值(应用程序需要每帧更新一次视觉内容,50毫秒的停止会使其延迟)

问题是线程导致应用程序在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);
        }
    }
IEnumerator人脸检测()
{
while(true)
{
如果(faceDetectionThreadDone)
{
rgbaMat=webCamTextureToMatHelper.GetMat();
if(rgbaMat!=null)
{
OpenCVForUnityUtils.SetImage(faceLandmarkDetector,rgbaMat);
faceDetectionThreadDone=false;
新线程(()=>
{
Thread.CurrentThread.IsBackground=true;
//重型计算设备(50毫秒)
List detectResult=faceLandmarkDetector.Detect();
如果(detectResult.Count>0)
{
points=faceLandmarkDetector.DetectLandmark(detectResult[0]);
}
faceDetectionThreadDone=true;
}).Start();
}
}
收益率返回新WaitForSeconds(0.1f);
}
}
我如何创建新线程是否存在严重问题?我在某个地方读到过,一旦执行完毕,它们就会被垃圾收集器清理掉。这可能会导致延迟吗?构建设置设置为高性能等

编辑:好的,我现在非常确定这个问题与内存管理无关。我在Xcode中运行了内部分析器,并观察了堆的使用量。当垃圾收集器启动时,性能没有受到影响


我测试应用程序的设备:iPhone 6、索尼Z3、三星S4创建和启动
线程
非常昂贵。每次

Thread(() =>
{
//Code
}).Start();
调用时,将分配大约1MB的内存。添加在其中发生的其他内存分配,例如
列表
(detectResult)创建

同时,
产生返回新的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 
不要真的认为这是主要问题,但我把它告诉你,你可以做到这一点。对于我上面提到的
线程
问题,您应该创建一个
while
循环,该循环处理数据,然后在主
线程
中执行输出。基本上是一个线程函数,它将永远循环,而不是每次都创建一个新的
线程

有一个名为的插件,允许您从另一个线程调用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
。分配足够的阵列内存一次,然后重新使用。这将完全删除应用程序中的内存分配。

创建和启动
线程
非常昂贵。每次

Thread(() =>
{
//Code
}).Start();
调用时,将分配大约1MB的内存。添加在其中发生的其他内存分配,例如
列表
(detectResult)创建

同时,
产生返回新的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 
不要真的认为这是主要问题,但我把它告诉你,你可以做到这一点。对于我上面提到的
线程
问题,您应该创建一个
while
循环,该循环处理数据,然后在主
线程
中执行输出。基本上是一个线程函数,它将永远循环,而不是每次都创建一个新的
线程

有一个名为的插件,允许您从另一个线程调用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
。分配足够的阵列内存一次,然后重新使用。这将完全删除应用程序中的内存分配。

将Application.targetFrameRate设置为1/30帧中的15,29/30帧中的60解决了此问题。。。。。。