2016-02-27 29 views
0

我以爲我在.NET中有線程,但是當我添加了LINQ表達式時,它讓我有點困惑。異步函數不返回控制到主線程(linq表達式)

就像我在這個討論的主題中寫的,我不爲什麼線程不會將控制返回到我的控制器的主要操作。 我已經寫了什麼讓我在評論傻了,所以讓我跳到真實的例子:

public class ValuesController : ApiController 
    { 
     public async Task<List<SomeProduct>> Get() 
     { 
      var collection = new List<Mother>() { 
       new Mother() 
       { 
        internalField = new List<Child>() 
        { 
         new Child() 
         { 
          theLastOne = "VAL" 
         }, 
         new Child() 
         { 
          theLastOne = "VAL" 
         } 
        } 
       } 
      }; 
      var oss = 
       from m in collection 
       from s in m.internalField 
       select Convert(m, s).Result; 
      //1-The above code doesnt enter into CONVERT function (I have a breakpoint there) 

      return oss.ToList();//2- this list enter into COnvertt 
     } 

     private async Task<SomeProduct> Convert(Mother ms, Child ss) 
     { 
      var ossNEW = new SomeProduct(); 
      await update(ossNEW, ms); 
      return ossNEW; 
     } 

     private async Task update(SomeProduct oss, Mother ms) 
     {//3 - Naturally it comes here 
      await Task.Run(()=> 
      { 
       //This task is executed (It is example code, pls do not care, that threads do not have any sense 
       oss.copyOfTheLastOne = ms.internalField.First().theLastOne; 
       oss.valeFromAnUpdateFunction = "works"; 
      }); //Flow comes here and THIS line does not return control to the main action, why? :) 
     } 
    } 

    public class SomeProduct 
    { 
     public string copyOfTheLastOne; 
     public string valeFromAnUpdateFunction; 

    } 
    public class Mother 
    { 
     public List<Child> internalField; 

    } 

    public class Child 
    { 
     public string theLastOne; 
    } 

我已經通過添加一個「執行者」,這需要的任務列表,並管理它解決了這個例子。

public class ValuesController : ApiController 
    { 
     public async Task<List<SomeProduct>> Get() 
     { 
      var collection = new List<Mother>() { 
       new Mother() 
       { 
        internalField = new List<Child>() 
        { 
         new Child() 
         { 
          theLastOne = "VAL" 
         }, 
         new Child() 
         { 
          theLastOne = "VAL" 
         } 
        } 
       } 
      }; 
      var oss = 
       from m in collection 
       from s in m.internalField 
       select Convert(m, s); 

      List<Task<SomeProduct>> downloadTasks = oss.ToList(); 
      List<SomeProduct> ossNew = new List<SomeProduct>(); 

      while (downloadTasks.Count > 0) 
      { 
       var firstFinishedTask = await Task.WhenAny(downloadTasks); 

       downloadTasks.Remove(firstFinishedTask); 
       ossNew.Add(await firstFinishedTask); 
      } 

      return ossNew; 
     } 

     private async Task<SomeProduct> Convert(Mother ms, Child ss) 
     { 
      var ossNEW = new SomeProduct(); 
      await update(ossNEW, ms); 
      return ossNEW; 
     } 

     private async Task update(SomeProduct oss, Mother ms) 
     { 
      await Task.Run(()=> 
      { 
       oss.copyOfTheLastOne = ms.internalField.First().theLastOne; 
       oss.valeFromAnUpdateFunction = "works"; 
      }); 
     } 

要充分認識這個問題,我想知道爲什麼更新功能並不控制返回到主行動,爲什麼CONVERT函數結果並不強制同步運行的程序?

+2

'異步'[不是線程](http://stackoverflow.com/q/17661428/11683)。 – GSerg

回答

1

我想知道爲什麼UPDATE函數不會將控制權返回給主動作,以及爲什麼RESULT函數不會強制同步運行程序?

您正在運行到common deadlock problem,我完全是由於使用的Result解釋在我的博客。使用await而不是Result,你的問題解決了(你的情況,因爲你有一個集合,你要await Task.WhenAll):

public async Task<SomeProduct[]> Get() 
{ 
    var collection = new List<Mother>() { 
     new Mother() 
     { 
     internalField = new List<Child>() 
     { 
      new Child() 
      { 
      theLastOne = "VAL" 
      }, 
      new Child() 
      { 
      theLastOne = "VAL" 
      } 
     } 
     } 
    }; 
    var oss = 
     from m in collection 
     from s in m.internalField 
     select Convert(m, s); 
    return Task.WhenAll(oss); 
} 

在一個側面說明,你不應該在你的實現使用Task.Run特別是在ASP.NET上。在ASP.NET上,Task.Run完全消除了async的所有好處,增加了開銷。

+0

太棒了!這是我的預期!謝謝 – Lukasz