2012-11-07 52 views
3

我需要將格式爲「HHmmss」的字符串快速轉換爲DateTime或整數。我測試這樣的代碼:將字符串「172406」轉換爲整數17,24,06快速

Console.WriteLine("decoding " + text); 
long microseconds = sw.ElapsedTicks/(Stopwatch.Frequency/(1000L * 1000L)); 
Console.WriteLine("start time " + microseconds); 
field = DateTime.ParseExact(text, "HHmmss", null); 
microseconds = sw.ElapsedTicks/(Stopwatch.Frequency/(1000L * 1000L)); 
Console.WriteLine("finish time " + microseconds); 

並且輸出是

 
decoding 172400 
start time 121 
finish time 244 

decoding 172400 
start time 236 
finish time 383 

decoding 172400 
start time 116 
finish time 416 

decoding 172400 
start time 235 
finish time 421 

decoding 172359 
start time 149 
finish time 323 

所以在平均約150微秒。有很多時候,我正在寫HFT軟件,最好的HFT平均有10微秒的「嘀嗒交易」時間(這包括所有事情!)。我明白,使用C#這是不可能的,但我仍然認爲,即使使用C#,150微秒也是太多了。

現在我想用另一種算法,但我不知道如何從文本「提取」的整數:

field = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, /*extract hour, min, sec from text*/) 

你能提出什麼會是最快的方法是什麼? 請不要問我爲什麼關心perfomance,而只是建議如何更快地做到這一點。

結果:

使用DateTime.ParseExact(text, "HHmmss", null)約6-8蜱

使用TimeSpan ts = TimeSpan.ParseExact(text, "hhmmss", null);約3-4蜱

使用int hour = 10 * text[0] + text[1] - 11 * '0'; ...約0蜱

NOTE:事實上遠遠低於如果使用循環進行測量,則爲0。事實上,它發現最後的版本比其他版本快100倍。

代碼:

long startMicroseconds = sw.ElapsedTicks /*/ (Stopwatch.Frequency/(1000L * 1000L))*/; 

    //TimeSpan ts = TimeSpan.ParseExact(text, "hhmmss", null); 

    //int hour = 10 * text[0] + text[1] - 11 * '0'; 
    //int minute = 10 * text[2] + text[3] - 11 * '0'; 
    //int second = 10 * text[4] + text[5] - 11 * '0'; 

    field = DateTime.ParseExact(text, "HHmmss", null); 

    long finishMicroseconds = sw.ElapsedTicks /*/ (Stopwatch.Frequency/(1000L * 1000L))*/; 
    Console.WriteLine("elappsed " + (finishMicroseconds - startMicroseconds)); 
+9

這是一個不好的方法來計時。在循環中運行代碼並計算整個循環。然後獲得每次迭代的平均時間。 –

+0

@MarkByers,結果將是150 + - 50. – javapowered

+1

@javapowered:你測試過了,還是假設? – Mr47

回答

9

此方法不使用任何字符串子字符串或解析方法。它僅使用索引和簡單的算術題:

int hour = (s[0] - '0') * 10 + s[1] - '0'; 
int minute = (s[2] - '0') * 10 + s[3] - '0'; 
int second = (s[4] - '0') * 10 + s[5] - '0'; 

這下一個版本就是甚至可能更快,因爲計算已部分evaulated幫助編譯器。因此,它是稍硬閱讀和理解:

int hour = s[0] * 10 + s[1] - '0' * 11; 
int minute = s[2] * 10 + s[3] - '0' * 11; 
int second = s[4] * 10 + s[5] - '0' * 11; 

踢,你可能也想看看這是更快,但我懷疑這個代碼將是與前一版本:

int hour = s[0] * 10 + s[1] - 528; 
int minute = s[2] * 10 + s[3] - 528; 
int second = s[4] * 10 + s[5] - 528; 
+0

+1,因爲這可能是性能最好的一個。但是如果編譯器不會將所有三個版本都縮減到最後一個,我會感到很驚訝。 – Groo

+0

有兩個正確的答案,但我標記你的答案,因爲它提前1分鐘回答:) – javapowered

2

這真的是太慢了?

TimeSpan ts = TimeSpan.ParseExact("172406", "hhmmss", null); 
int hh = ts.Hours; 
int mm = ts.Minutes; 
int ss = ts.Seconds; 

這至少容易理解。

+0

這是大約70微秒什麼更好,但我仍然期望<10微秒 – javapowered

+3

我已經測量了4個帶秒錶的滴答聲。一微秒是1000個滴答聲。 –

+0

@Tim:我認爲'Stopwatch.Ticks'取決於操作系統和硬件。你能把它翻譯成毫秒嗎?而且,你是在一個更大的循環中測試它,還是隻測試一次? – Groo

3

如果你真的想表現的,而不是可讀性,您可以直接與原始字符工作:

hour = 10*s[0] + s[1] - 11*'0'; 
minute = 10*s[2] + s[3] - 11*'0'; 
second = 10*s[4] + s[5] - 11*'0'; 

順便說一句。 DateTime.Now非常慢,因爲它需要將當前時間轉換爲本地時區。您應該改用DateTime.UtcNow。在我的comp DateTime.UtcNow費用9ns,DateTime.Now費用900ns。

你也應該取DateTime.UtcNow只有一次,否則你會得到一個種族條件。

+1

不應該這是'-11 *'0''? – Henrik

+0

@Henrik修好了,謝謝 – CodesInChaos

+0

是的,我確實想要性能,而不是可讀性,謝謝你測試 – javapowered