2012-10-19 36 views
1

下面的代碼運行在大致2.5秒:與動態性能並行的對象

static void Main(string[] args) 
{ 
    var service = new Service(); 
    Parallel.For(0, 100, i => { 
     dynamic user = new ExpandoObject(); 
     user.data = new ExpandoObject(); 
     user.data.id = i; 
     user.data.name = "User Name"; 
     var parsed = service.Parse(user); 
    }); 
} 

public class Service 
{ 
    public User Parse(dynamic dynamicUser) 
    { 
     if (dynamicUser.data != null) 
     { 
      return new User 
      { 
       Id = dynamicUser.data.id, 
       Name = dynamicUser.data.name 
      }; 
     } 
     return null; 
    } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

然而,如果更改的Parallel.For()循環到一個簡單的For循環,它運行在大約200毫秒:

for (var i = 0; i < 100; i++) 

所以我的問題是,爲什麼在並行運行時是這麼多慢?

我的理論是在解析每個線程完成一次的動態對象時會有一些開銷。在簡單的循環中,DLR第一次完成它的事情,然後不需要爲每個後續的呼叫。

但並行地,DLR的開銷發生在每次調用中。

這是一個正確的假設,或我的方式基地?

+1

首先確保使用發佈版本。當我運行你的代碼時,我在調試模式下獲得了類似的時間,但在釋放模式下只有0.07秒。它仍然更高,但要低得多。 (雖然常規for循環會下降很多。) – Servy

回答

3

我懷疑你被你的診斷誤導了。特別是,如果運行循環需要2.5秒,那真的很慢。這是在調試器下,有沒有機會?

下面是我的箱子上用/o+編譯的代碼的結果,然後在控制檯中運行。請注意,我在每個測試中都運行了1,000,000次循環迭代。

Void ExecuteParallel(): 00:00:00.7311773 
Void ExecuteSerial(): 00:00:02.0514120 
Void ExecuteParallel(): 00:00:00.6897816 
Void ExecuteSerial(): 00:00:02.0389325 
Void ExecuteParallel(): 00:00:00.6754025 
Void ExecuteSerial(): 00:00:02.0653801 
Void ExecuteParallel(): 00:00:00.7136330 
Void ExecuteSerial(): 00:00:02.0477593 
Void ExecuteParallel(): 00:00:00.6742260 
Void ExecuteSerial(): 00:00:02.0476146 

這不是儘可能多並行快,你可能期望從一個四核i7處理器,但我懷疑這是由於上下文切換等由Servy提到的 - 也可能在執行高速緩存爭DLR。儘管如此,它的運行速度要比系列運行速度快。

嘗試自己的代碼,看看你在你的盒子上 - 但不是在調試器下。

代碼:

using System; 
using System.Diagnostics; 
using System.Dynamic; 
using System.Threading.Tasks; 

class Test 
{ 
    const int Iterations = 1000000; 

    static void Main(string[] args) 
    { 
     for (int i = 0; i < 5; i++) 
     { 
      RunTest(ExecuteParallel); 
      RunTest(ExecuteSerial); 
     } 

    } 

    static void RunTest(Action action) 
    { 
     var sw = Stopwatch.StartNew(); 
     action(); 
     sw.Stop(); 
     Console.WriteLine("{0}: {1}", action.Method, sw.Elapsed); 
    } 

    static void ExecuteParallel() 
    { 
     var service = new Service(); 
     Parallel.For(0, Iterations, i => { 
      dynamic user = new ExpandoObject(); 
      user.data = new ExpandoObject(); 
      user.data.id = i; 
      user.data.name = "User Name"; 
      var parsed = service.Parse(user); 
     }); 
    } 

    static void ExecuteSerial() 
    { 
     var service = new Service(); 
     for (int i = 0; i < Iterations; i++) 
     { 
      dynamic user = new ExpandoObject(); 
      user.data = new ExpandoObject(); 
      user.data.id = i; 
      user.data.name = "User Name"; 
      var parsed = service.Parse(user); 
     } 
    } 
} 

public class Service 
{ 
    public User Parse(dynamic dynamicUser) 
    { 
     if (dynamicUser.data != null) 
     { 
      return new User 
      { 
       Id = dynamicUser.data.id, 
       Name = dynamicUser.data.name 
      }; 
     } 
     return null; 
    } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 
+0

確實是調試器 - 當調試器沒有運行時,結果與您的結果非常相似。任何想法爲什麼調試器造成這樣的打擊? – MrDustpan

+2

@MrDustpan必須禁用所有優化才能使用調試器,並且優化會影響性能測試。 – Servy

1

在這裏,你所做的任務非常簡單,只需要很少的時間,而且它們很少,創建線程,分解任務,調度它們,處理上下文切換,內存的開銷障礙以及所有這些,與您正在從事的生產性工作量相比,意義重大。如果你在做的工作花費的時間更長,那麼平行化的開銷就會小得多。