Unity - 如何减少在Update和GC中花费的时间

时间:2016-08-19 04:48:56

标签: c# python multithreading unity3d garbage-collection

我在Unity中有与另一个Python应用程序交换数据的脚本。它有一个while循环,它监听UDP消息作为后台线程。此外,脚本还通过更新功能每帧请求新数据。

收到消息后,脚本将其解析为字符串,并且需要按标签拆分字符串以检索所有值。目前,该字符串包含Unity需要作为播放器输入的眼球跟踪器和操纵杆数据。

UDPController.cs

private void init()
{

    // define address to send data to
    pythonEndPoint = new IPEndPoint(IPAddress.Parse(IP), pythonPort);
    unityEndPoint = new IPEndPoint (IPAddress.Parse (IP), unityPort);
    pythonSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);


    //define client to receive data at
    client = new UdpClient(unityPort);
    client.Client.ReceiveTimeout = 1;
    client.Client.SendTimeout = 1;

    // start background thread to receive information
    receiveThread = new Thread(new ThreadStart(ReceiveData));
    receiveThread.IsBackground = true;
    receiveThread.Start();

}

void Update(){
    if (Calibration.calibrationFinished && startRequestNewFrame) {
        RequestData();
    }
}
private void RequestData() {
    // Sends this to the UDP server written in Python
    SendString("NEWFRAME");
}

// receive thread which listens for messages from Python UDP Server
private void ReceiveData()
{

    while (true)
    {

        try
        {

            if(client.Available > 0) {

                double unixRecvTimeStamp = DataManager.ConvertToUnixTimestamp(DateTime.Now);
                byte[] data = client.Receive(ref pythonEndPoint);

                string rawtext = Encoding.UTF8.GetString(data);

                string[] msgs = rawtext.Split('\t');

                string msgType = msgs[0];
                double pythonSentTimeStamp = double.Parse(msgs[msgs.Length-1].Split(' ')[1]);

                DataManager.UdpRecvBuffer += '"' + rawtext + '"' + "\t" + pythonSentTimeStamp + "\t" + unixRecvTimeStamp + "\t" + DataManager.ConvertToUnixTimestamp(DateTime.Now) + "\n";

                if (String.Equals(msgType, "FRAMEDATA"))
                {

                    DataManager.gazeAdcsPos = new Vector2(float.Parse(msgs[1].Split(' ')[1]), float.Parse(msgs[2].Split(' ')[1]));
                    float GazeTimeStamp = float.Parse(msgs[3].Split(' ')[1]);
                    DataManager.rawJoy = new Vector2(float.Parse(msgs[4].Split(' ')[1]), 255 - float.Parse(msgs[5].Split(' ')[1]));
                    float joyC = float.Parse(msgs[6].Split(' ')[1]);
                    float ArduinoTimeStamp = float.Parse(msgs[7].Split(' ')[1]);
                }

            }

        }
        catch (Exception err)
        {
            print(err.ToString());
        }
    }
}

因此,根据Unity Profiler,似乎在行为更新中花费了大量时间,特别是在UDPController.Update()和GC.Collect中。我最初的假设是,我可能会超时创建太多的字符串和数组,并且垃圾收集器会经常启动以删除未使用的内存空间。

Unity Profiler - Showing high CPU Usage and Time in Behaviour Update

所以我的问题是,我的假设是对的吗?如果是这样,我如何重写此代码以提高我的性能并减少FPS和感知延迟的下降。如果没有,那么问题出在哪里,因为目前游戏开始滞后约10分钟。

此外,有更好的数据传输方式或格式吗?好像我可以使用像JSON,Google Protocol Buffer或msgpack这样的对象,或者这会是一种矫枉过正的行为吗?

1 个答案:

答案 0 :(得分:0)

  1. 我可以在你的while循环中看到很多局部变量(以及数组)。本地变量导致垃圾收集器运行。您应该声明方法之外的所有变量。

  2. 此外,请避免将while/update()中的字符串操作设为strings are immutable。因此,您的代码会创建一个新副本,以便在每次连接后存储结果。在这些情况下使用StringBuilder以避免GC。

  3. Read More