2014-10-20 41 views
4

我通過lambda表達式創建了一批匿名函數。我想使用TaskId來區分匿名函數。 下面是代碼:這是由C#編譯器完成的優化嗎?

int count = 3; 
int i; 
for (int j = 0; j < 10; j++) 
{ 
    i = 0; 
    Func<bool, Task<int>> func = async (b) => 
    { 
     return j; 
    }; 
    while (i++ < count) 
    { 
     var task = func(true); 
     Console.WriteLine(String.Format("Task Result:{0} TaskId:{1}", 
      task.Result, task.Id)); 
    } 
} 

這裏是輸出

Task Result:0 TaskId:1 
Task Result:0 TaskId:1 
Task Result:0 TaskId:1 
Task Result:1 TaskId:2 
Task Result:1 TaskId:2 
Task Result:1 TaskId:2 
Task Result:2 TaskId:3 
Task Result:2 TaskId:3 
Task Result:2 TaskId:3 
Task Result:3 TaskId:4 
Task Result:3 TaskId:4 
Task Result:3 TaskId:4 
Task Result:4 TaskId:5 
Task Result:4 TaskId:5 
Task Result:4 TaskId:5 
Task Result:5 TaskId:6 
Task Result:5 TaskId:6 
Task Result:5 TaskId:6 
Task Result:6 TaskId:7 
Task Result:6 TaskId:7 
Task Result:6 TaskId:7 
Task Result:7 TaskId:8 
Task Result:7 TaskId:8 
Task Result:7 TaskId:8 
Task Result:8 TaskId:9 
Task Result:8 TaskId:9 
Task Result:8 TaskId:9 
Task Result:9 TaskId:10 
Task Result:9 TaskId:11 
Task Result:9 TaskId:12 

正如你所看到的,改變的taskid因爲結果是大於8我不知道到知道這樣做的原因現象。感謝您的幫助:)

+0

有趣的是,從我可以告訴它重用任務實例(object.ReferenceEquals在比較'task'到上一個值時爲true)一段時間,但它不清楚爲什麼。 – 2014-10-20 04:30:23

+0

@mikez是的。但我不知道爲什麼返回值會影響重用。 – 2014-10-20 05:09:32

+0

任務正在緩存某處。在連續兩次的方法中運行該代碼。對於<= 8,相同的任務id會重複,但在此之上它們是新的。 – 2014-10-20 05:17:56

回答

2

這不是編譯器本身,而是執行緩存的.NET框架。查看AsyncMethodBuilder的代碼,編譯器使用該代碼管理生成的異步方法的狀態機。它看起來像SetResultGetTaskForResult中做了一些緩存。還有用於緩存的基本價值類型,包括這一些非常具體的代碼:

// For Int32, we cache a range of common values, e.g. [-1,4). 
else if (typeof(TResult) == typeof(Int32)) 
{ 
    // Compare to constants to avoid static field access if outside of cached range. 
    // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the 
    // lower side, due to positive values being more common than negative as return values. 
    Int32 value = (Int32)(object)result; 
    if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX && 
     value >= AsyncTaskCache.INCLUSIVE_INT32_MIN) 
    { 
     Task<Int32> task = AsyncTaskCache.Int32Tasks[value - AsyncTaskCache.INCLUSIVE_INT32_MIN]; 
     return JitHelpers.UnsafeCast<Task<TResult>>(task); // UnsafeCast avoids a type check we know will succeed 
    } 
} 

而且我們看到的是:

/// <summary>The minimum value, inclusive, for which we want a cached task.</summary> 
internal const Int32 INCLUSIVE_INT32_MIN = -1; 
/// <summary>The maximum value, exclusive, for which we want a cached task.</summary> 
internal const Int32 EXCLUSIVE_INT32_MAX = 9; 

這就是爲什麼8是神奇的截止。值得注意的是-1也應該得到緩存,並從我的測試中得到。

+0

很好的答案。非常感謝! – 2014-10-20 05:31:33

0

ambda表達式存儲變量而不是值。你的表情是異步的,所以我認爲線程搞亂了結果。嘗試沒有異步魔法,它會顯示正確的結果。

+0

該代碼是一個示例。我真的很想知道爲什麼會發生混亂。 – 2014-10-20 04:57:01