2013-03-05 97 views
24

EDIT3:

使用,而不是爲什麼Java中的字符串比較(CompareTo)比C#更快?

StringComparer comparer1 = StringComparer.Ordinal; 

IComparable v 
IComparable w 
comparer1.Compare(v, w) 

解決運行時的問題。


我已經做了Java和C#的排序算法(例如快速排序,歸併排序)一些基準。

我使用Java 7和.NET Framework 4.5來實現和執行我的算法。它表明所有的算法都可以使用Java實現更好的運行時間。

對於快速排序的一些示例的運行時間:

C#

  1. N =百萬4433毫秒
  2. N = 2000000 10047毫秒

爪哇

  1. N =百萬1311毫秒
  2. N = 2000000 3164毫秒

使用分析工具然後我已經做了措施:C#所使用的運行時對字符串比較的75%(即CompareTo),而Java僅使用運行時的2%進行比較。

爲什麼字符串比較在C#中而不是在Java中如此昂貴?我已經測試了C#排序函數Arrays.sort(INPUT)它可以實現約3000毫秒的n = 1000000,所以我不認爲代碼是問題。但不管怎麼說:

下面的代碼爲快速排序:

public class Quicksort { 

public static void sort(IComparable[] a) { 
    sort(a, 0, a.Length - 1); 
} 

private static void sort(IComparable[] a, int lo, int hi) { 
    if (hi <= lo) return; 
    int j = partition(a, lo, hi); 
    sort(a, lo, j-1); 
    sort(a, j+1, hi); 
} 

private static int partition(IComparable[] a, int lo, int hi) { 
    int i = lo; 
    int j = hi + 1; 
    IComparable v = a[lo]; 
    while (true) { 

     while (less(a[++i], v)) 
      if (i == hi) break; 

     while (less(v, a[--j])) 
      if (j == lo) break; 


     if (i >= j) break; 

     exch(a, i, j); 
    } 

    exch(a, lo, j); 

    return j; 
} 


public static IComparable select(IComparable[] a, int k) { 
    if (k < 0 || k >= a.Length) { 
     throw new Exception("Selected element out of bounds"); 
    } 
    Rnd.Shuffle(a); 
    int lo = 0, hi = a.Length - 1; 
    while (hi > lo) { 
     int i = partition(a, lo, hi); 
     if  (i > k) hi = i - 1; 
     else if (i < k) lo = i + 1; 
     else return a[i]; 
    } 
    return a[lo]; 
} 


private static bool less(IComparable v, IComparable w) { 
    return (v.CompareTo(w) < 0); 
} 

private static void exch(Object[] a, int i, int j) { 
    Object swap = a[i]; 
    a[i] = a[j]; 
    a[j] = swap; 
} 

} 

快速排序進行測量計算方式如下:

Stopwatch.Restart(); 
Quicksort.sort(stringArray); 
Stopwatch.Stop(); 

EDIT2:有人想看看Java版本。這是完全一樣的我只是使用Comparable而不是IComparable和Array.length而不是Array.Length

+10

請顯示您正在使用的代碼。有很多事情可能會影響到這一點。 – 2013-03-05 00:17:52

+1

我對這裏發生的事情有懷疑*,但我正在等待看代碼。 – 2013-03-05 00:23:10

+2

@RBarryYoung我不認爲他想在這裏提出任何要求。我認爲他在做出正確的事情,試圖在得出結論之前確定可能的原因。但的確我們需要看到測試方法來幫助他們。 – AaronLS 2013-03-05 00:26:14

回答

24

,所以我不認爲這個代碼是我不敢苟同問題

。在這兩種情況下,你都沒有比較相同的東西。無可否認,還有沒有向我們展示如何生成字符串等,但Java和.NET執行不同的默認字符串比較。

從Java的String.compareTo

比較兩個字符串按字典順序。

而從.NET的String.CompareTo

此方法執行字(區分大小寫和文化敏感)使用當前區域性比較。

毫不奇怪,這比純粹的詞典對比要慢。

人們很容易看到這個的時候只是自己比較.NET ...

using System; 
using System.Diagnostics; 
using System.Text; 

class Test 
{ 
    static void Main() 
    { 
     string[] source = GenerateRandomStrings(); 
     string[] workingSpace = new string[source.Length]; 

     CopyAndSort(source, workingSpace); 
     Stopwatch sw = Stopwatch.StartNew(); 
     for (int i = 0; i < 1000; i++) 
     { 
      CopyAndSort(source, workingSpace); 
     } 
     sw.Stop(); 
     Console.WriteLine("Elapsed time: {0}ms", 
          (long) sw.Elapsed.TotalMilliseconds); 
    } 

    static string[] GenerateRandomStrings() 
    { 
     Random rng = new Random(); 
     string[] ret = new string[10000]; 
     for (int i = 0; i < ret.Length; i++) 
     { 
      ret[i] = GenerateRandomString(rng); 
     } 
     return ret; 
    } 

    static string GenerateRandomString(Random rng) 
    { 
     char[] chars = new char[30]; 
     for (int i = 0; i < chars.Length; i++) 
     { 
      chars[i] = (char) rng.Next('A', 'z' + 1); 
     } 
     return new string(chars); 
    } 

    static void CopyAndSort(string[] original, string[] workingSpace) 
    { 
     Array.Copy(original, 0, workingSpace, 0, original.Length); 
     Array.Sort(workingSpace); 
     // Array.Sort(workingSpace, StringComparer.Ordinal); 
    } 
} 

自己嘗試一下,不同的依據是否指定一個有序的字符串比較器或不CopyAndSort方法。這是很多與序數比較器,至少在我的盒子上更快。

+0

在測量之前您有一次調用'CopyAndSort'的原因嗎?還是隻是爲了確保每次運行都以相同的'workingSpace'狀態(即排序)開始? – poke 2013-03-05 00:55:17

+7

@poke:不是,它是在開始測量之前確保它已全部通過JIT編譯。 – 2013-03-05 00:55:39

+0

啊我看到了,這很有道理 - 謝謝:) – poke 2013-03-05 00:56:24

9

我不是100%確定,但我認爲在C#中.Net平臺可能會默認執行一些擴展檢查正確跳過註釋或空格unicode字符和Java可能不會默認執行它們。我認爲Java的運行時執行簡單的字節2字節比較,但我可能在這裏是非常錯誤的,因爲我已經摸索了使用Java中的編碼工作的相當長的時間,所以這是純粹的猜測。

另一件事:這兩個平臺之間的默認比較行爲可能存在一些差異。如果你只是使用默認值,沒有任何精確的設置,我猜你只是隱式地要求不同的行爲。

至少在.Net中有很多字符串比較選項。它可能發生了,你只是採取了類似的功能,實際上做了與Java的不同比較。你有沒有試過像http://msdn.microsoft.com/en-us/library/cc190416.aspx這樣的詳細過載?請注意,這是區別地使用有點static方法:

var result1 = "mom".CompareTo("dad"); 
var result2 = string.Compare("mom", "dad", ...); 

請調查ComparisonOptions和/或CultureInfo的設置,使整體行爲密切Java的行爲相匹配地進行調整。另外,如果還有更多的話,你可能不得不在Java端選擇一個不同的超載。另外,另一個區別可能有些棘手的事實是,您正在測試的CompareTo方法是實現IComparable<T>接口,該接口旨在交叉比較實現此接口的各種對象,並且靜態方法被設計爲只比較字符串。他們可能會針對不同的事情進行優化。如果它們之間會有任何性能差異,我敢打賭靜態Compare對於字符串vs字符串比較更快。

+0

那麼我還測試了C#排序方法Arrays.Sort(輸入)和Collection.Sort(),其含鉛到3000個毫秒運行時對於n = 1000000所以Java仍然爲300%的速度。 – 2013-03-05 00:33:53

+0

默認無參數Arrays.Sort和Collection.Sort總是使用最通用的IComparable接口,因爲它沒有任何其他選項。這些功能被設計爲「簡單易用」,而不是「最快」或「最輕」。他們甚至不得不檢查LHS和RHS是否具有相同的類型,從而更加符合性能。要精細定製性能,您可能需要使用排序算法,該排序算法至少要**使用「comparer」或「比較委託」,您可以在其中指定確切的比較行爲。但是,讓我再說一遍:我寫的所有內容都只是猜測。 – quetzalcoatl 2013-03-05 00:40:10

+4

@ user2025998:嘗試指定'StringComparer.Ordinal'作爲使用的比較的相同測試。基本上,Java默認使用序數比較,.NET不使用。 – 2013-03-05 00:40:24