Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 没有内存分配的委托闭包_C#_Multithreading_Unity3d_Delegates_Closures - Fatal编程技术网

C# 没有内存分配的委托闭包

C# 没有内存分配的委托闭包,c#,multithreading,unity3d,delegates,closures,C#,Multithreading,Unity3d,Delegates,Closures,我编写了一个线程助手类,可用于在Unity的主线程中执行一段代码 这是功能蓝图: public static void executeInUpdate(System.Action action) 完整的脚本确实很长,这将使这篇文章变得不必要的长。您可以看到脚本助手类的其余部分 然后我可以从另一个线程使用unity的API,如下所示: UnityThread.executeInUpdate(() => { transform.Rotate(new Vector3(0f, 90f,

我编写了一个线程助手类,可用于在Unity的主线程中执行一段代码

这是功能蓝图:

public static void executeInUpdate(System.Action action)
完整的脚本确实很长,这将使这篇文章变得不必要的长。您可以看到脚本助手类的其余部分

然后我可以从另一个
线程使用unity的API,如下所示:

UnityThread.executeInUpdate(() =>
{
    transform.Rotate(new Vector3(0f, 90f, 0f));
});
问题是,当我使用在该委托外部声明的变量时,它会分配内存。上面的代码为每帧分配104字节。这是因为在闭包中使用了
transform
变量

这可能看起来没什么,但我每秒做60次,我有6个摄像头需要连接并在屏幕上显示图像。我不喜欢产生的垃圾量

下面是我如何从相机下载图像并将其上传到Unity的示例。我每秒大约得到60帧。
receiveVideoFrame()
函数在单独的线程上运行。它下载图像,将其发送到Unity的主
线程
,然后Unity将图像上传到。然后显示
纹理2d
。由于
UnityThread.executeInUpdate
捕获闭包时发生分配

bool doneUploading = false;
byte[] videoBytes = new byte[25000];
public Texture2D videoDisplay;

void receiveVideoFrame()
{
    while (true)
    {
        //Download Video Frame 
        downloadVideoFrameFromNetwork(videoBytes);

        //Display Video Frame 
        UnityThread.executeInUpdate(() =>
        {
            //Upload the videobytes to Texture to display
            videoDisplay.LoadImage(videoBytes);
            doneUploading = true;
        });

        //Wait until video is done uploading to Texture/Displayed
        while (!doneUploading)
        {
            Thread.Sleep(1);
        }

        //Done uploading Texture. Now set to false for the next run
        doneUploading = false;

        //Repeat again
    }
}
如何使用闭包而不导致内存分配

如果这是不可能的,还有其他方法吗


我可以删除用于在主线程中执行代码的类,然后在主脚本中重新编写这些逻辑,但这将是混乱和漫长的

经过数小时的实验后,我发现如果将带有闭包的代码放入函数中,然后将其缓存到
启动
唤醒
函数中的
操作
变量一次,则在while循环中调用闭包时,闭包内存分配将消失

另外,我将
doneuplooding
布尔变量设置为
volatile
,这样两个
线程都可以看到更改。我认为这里的
boolean
变量不需要
lock
关键字

private volatile bool doneUploading = false;

byte[] videoBytes = new byte[25000];
public Texture2D videoDisplay;

Action chachedUploader;

void Start()
{
    chachedUploader = uploadToTexture;
}

void uploadToTexture()
{
    UnityThread.executeInUpdate(() =>
    {
        //Upload the videobytes to Texture to display
        videoDisplay.LoadImage(videoBytes);
        doneUploading = true;
    });
}

//running in another Thread
void receiveVideoFrame()
{
    while (true)
    {
        //Download Video Frame 
        downloadVideoFrameFromNetwork(videoBytes);

        //Display Video Frame (Called on main thread)
        UnityThread.executeInUpdate(chachedUploader);

        //Wait until video is done uploading to Texture/Displayed
        while (!doneUploading)
        {
            Thread.Sleep(1);
        }

        //Done uploading Texture. Now set to false for the next run
        doneUploading = false;

        //Repeat again
    }
}

如果有人发现任何不好的地方,我愿意做更多的改进。虽然,我已经解决了我的问题。闭包不再分配内存。

您将调用嵌套到
executeInUpdate
。您只需要在我所能看到的范围内缓存最里面的代理。如果你真的想参与进来,我想你可以使用内存屏障,而不是依赖于
volatile
,但这可能需要更多的思考。@RobH“你只需要缓存我能看到的最里面的委托”有没有替代的例子?这样做行吗?你可能仍然需要动作场,但我认为你不应该。@RobH谢谢你。我刚刚试过,它分配了104个字节,这就是我试图消除的问题。通过将其缓存到
Action
中,它根本不会进行分配。太奇怪了。我不是说锁,就像你说的那样,那太过分了,太贵了。我的意思是使用
Thread.MemoryBarrier
,但是
volatile
绝对可以而且更简单。