嘿伙计们,所以我做了这个函数,它每帧都调用。 - 您认为这是保存性能的好方法还是有更好的方法?
private void GetCurrentTime()
{
m_TimeNow = System.Convert.ToString(System.DateTime.Now);
//If the previous time is not equals to the current time (without seconds = every minute)
if (m_PreTime != m_TimeNow.Remove(14))
{ //Change the Time displayed on the screen:
m_PreTime = m_TimeNow.Remove(14); //1. Copy current Time
m_Times = m_TimeNow.Split(' '); //2. Split to following parts
m_Time = m_Times[1].Remove(4); //3. Cutout seconds
m_Text_Time.text = m_Time + " " + m_Times[2]; //4. And change UI-Text: Time + AM/PM
}
}
此函数称为每个帧,并将在移动安卓设备上。
谢谢!
我可能会在您的实现中看到一些改进。这是我从自己的经验中可以告诉你的。
对于简短的回答,这是我编写函数的方式:
//
// Version 2
//
class TimerExample_V2 {
private DateTime _TimeNow = System.DateTime.Now;
private DateTime _PreTime = System.DateTime.Now;
private string _format = "t";
private string _cultureName = "en-US";
public TimerExample_V2() {
CultureInfo culture = new CultureInfo(_cultureName);
CultureInfo.CurrentCulture = culture;
}
public void UpdateCurrentTimeUI() {
_TimeNow = System.DateTime.Now;
if(_PreTime.Minute != _TimeNow.Minute) {
// Note: this case appear only once per minute.
_PreTime = System.DateTime.Now;
string newText = _TimeNow.ToString(_format);
//m_Text_Time.text = newText; // Update unity display
// I omit this display unity. (Same cost in both case)
}
}
现在有一个更长的答案和解释:
字符串(性能): 字符串通常很昂贵,尤其是在处理 str 处理和比较时。例如,'String.Remove(int)' 创建了一个新字符串,它可能会调用几个昂贵的方法,如 malloc 等(幕后)。据我所知,您将所有日期保留为字符串,但只能使用原始格式 DateTime。更好的方法是将数据保留为"日期时间"格式,并将其转换为仅供最终用户使用的字符串。(例如,更新您的 Unity 显示)。比较两个 int (例如: DateTime.ElapsedMilliseconds) 比比较字符串 (例如: m_PreTime != m_TimeNow.Remove(14))
更好日期格式(灵活性): 处理不同的日期格式时,您会遇到几个问题。您的实现需要"HH:mm AM/PM"格式,但用户可能有可能更改格式(例如24小时)。使用 C# 给你的黑暗魔法力量。例如,使用CultureInfo或已经实现的"DateTime.ToString(format)"。(我刚刚了解了"文化信息"。可能还有其他方法。但作为一般规则,查看该语言是否已经具有您需要的功能)。
函数名称: 这是一件小事,但尽量有小函数来做它所说的。在您的情况下,从"GetCurrentTime"开始,我们期望返回值。此函数实际上更新显示并返回无效。像"UpdateTimeDisplay"这样的东西可能更好。
重复呼叫: 第二件小事:您有 2 次调用 m_timeNow.Remove(14)。您可以创建一个新字符串一次(从此函数),并在两个位置都使用此新字符串。
实验(测量和验证)
无论如何,在处理性能时,您必须测量,基准测试您的代码。(举个例子,我首先为你的GetCurrentTime做了一个实现,并意识到它实际上并没有更好。以下是我创建的一些经验,向您展示一些测量方法。我不是 C# 萨满专家,也不是性能向导专家,但我希望我的例子足够清楚。我在笔记本电脑上运行实验:(英特尔i5-3320M CPU @ 2.60GHz)。
我有两个函数的实现。我每个函数运行 10 000 次,并打印每个函数的执行时间。(我省略了更新 Unity 显示的调用,这在两种情况下都是相同的)。我的测量显示,您的实现需要 45 毫秒,另一个需要 23 毫秒。
第二个实现听起来更好。但是,不要忘记我调用了10 000次函数。实际上,使用 60fps 时,每秒调用更新 60 次。在我的笔记本电脑上,60 次迭代都花了 0 毫秒。
还有另一个因素需要指出:
m_PreTime = m_TimeNow.Remove(14);
m_Times = m_TimeNow.Split(' ');
m_Time = m_Times[1].Remove(4);
自从处理字符串创建以来,这些是很慢的函数。但是,每分钟仅调用一次。作为一个问题,我测量了一下,我的实现在切换分钟时,使用与您的相同的毫秒数。我可能没有通过测量或其他什么,但也许,每分钟一次,我的函数花费的时间和你的一样多。在所有其他情况下,它"更快"。我可以用一句话来说明这一点:
"先解决最常见的情况,而不是最通用的情况">
(据我所知,这是关于优化的讨论中的一句话:https://www.youtube.com/watch?v=nXaxk27zwlk。顺便说一句,好话)
实验(源代码)
所以这是我可怕的实验的完整代码:
using System;
using System.Globalization;
using System.Diagnostics;
// Instructions to compile (With mono)
// csc Program.cs
// mono Program.exe
class Program {
static void Main(string[] args) {
TimerExample_V1 timer_v1 = new TimerExample_V1();
TimerExample_V2 timer_v2 = new TimerExample_V2();
Stopwatch profiler;
int nbBenchLoops = 10000; // 10 000 times
float t1;
float t2;
// Profil version 1
profiler = Stopwatch.StartNew();
for(int k = 0; k < nbBenchLoops; ++k) {
timer_v1.UpdateCurrentTimeUI();
}
t1 = profiler.ElapsedMilliseconds;
// Profil version 2
profiler = Stopwatch.StartNew();
for(int k = 0; k < nbBenchLoops; ++k) {
timer_v2.UpdateCurrentTimeUI();
}
t2 = profiler.ElapsedMilliseconds;
// Print mesured times
Console.WriteLine("[SCOPE_PROFILER] [Version 1]: {0} ms", t1);
Console.WriteLine("[SCOPE_PROFILER] [Version 2]: {0} ms", t2);
}
}
//
// Version 1
//
class TimerExample_V1 {
private string m_TimeNow = System.Convert.ToString(System.DateTime.Now);
private string m_PreTime = System.Convert.ToString(System.DateTime.Now);
private string[] m_Times;
private string m_Time;
public void UpdateCurrentTimeUI() {
m_TimeNow = System.Convert.ToString(System.DateTime.Now);
if (m_PreTime != m_TimeNow.Remove(14)) {
// Note: this case appear only once per minute.
m_PreTime = m_TimeNow.Remove(14);
m_Times = m_TimeNow.Split(' ');
m_Time = m_Times[1].Remove(4);
string newText = m_Time + " " + m_Times[2];
//m_Text_Time.text = newText; // Update unity display
// I omit this display unity. (Same cost in both case)
}
}
}
//
// Version 2
//
class TimerExample_V2 {
private DateTime _TimeNow = System.DateTime.Now;
private DateTime _PreTime = System.DateTime.Now;
private string _format = "t";
private string _cultureName = "en-US";
public TimerExample_V2() {
CultureInfo culture = new CultureInfo(_cultureName);
CultureInfo.CurrentCulture = culture;
}
public void UpdateCurrentTimeUI() {
_TimeNow = System.DateTime.Now;
if(_PreTime.Minute != _TimeNow.Minute) {
// Note: this case appear only once per minute.
_PreTime = System.DateTime.Now;
string newText = _TimeNow.ToString(_format);
//m_Text_Time.text = newText; // Update unity display
// I omit this display unity. (Same cost in both case)
}
}
}
有关 DateTime.ToString 和 CultureInformation 的更多信息,请查看文档:
- 文化信息 C# 文档
- 日期时间.到字符串 C# 文档
希望这对:)有所帮助