我在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中。我最初的假设是,我可能会超时创建太多的字符串和数组,并且垃圾收集器会经常启动以删除未使用的内存空间。
所以我的问题是,我的假设是对的吗?如果是这样,我如何重写此代码以提高我的性能并减少FPS和感知延迟的下降。如果没有,那么问题出在哪里,因为目前游戏开始滞后约10分钟。
此外,有更好的数据传输方式或格式吗?好像我可以使用像JSON,Google Protocol Buffer或msgpack这样的对象,或者这会是一种矫枉过正的行为吗?
答案 0 :(得分:0)
我可以在你的while循环中看到很多局部变量(以及数组)。本地变量导致垃圾收集器运行。您应该声明方法之外的所有变量。
此外,请避免将while/update()
中的字符串操作设为strings are immutable。因此,您的代码会创建一个新副本,以便在每次连接后存储结果。在这些情况下使用StringBuilder以避免GC。