C# 没有内存分配的委托闭包
我编写了一个线程助手类,可用于在Unity的主线程中执行一段代码 这是功能蓝图: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,
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
绝对可以而且更简单。