2014-10-07 67 views
0

我剛開始學習如何處理ASP.NET中的異步任務。我決定嘗試在我的一個方法中實現一些異步功能。我需要通過訪問數據庫來獲得3個不同的整數,分別命名爲按時,遲到,和incomp。這可以全部在同一時間完成,因爲方法中沒有其他方法依賴於這些調用的輸出。閱讀http://msdn.microsoft.com/en-us/library/hh524395.aspxhttp://msdn.microsoft.com/en-us/library/vstudio/hh191443(v=vs.110).aspx之後,這是我想出了代碼:正確的方式來運行這些異步任務?

public async Task<ActionResult> KPI(int id = 0) 
    { 
     var ontime = getOnTimeTasks(id); 
     var late = getLateTasks(id); 
     var incomp = getIncompleteTasks(id); 

     await System.Threading.Tasks.Task.WhenAll(ontime, late, incomp); 
     ViewData["ontime"] = ontime; 
     ViewData["ictasks"] = late; 
     ViewData["incomplete"] = incomp; 

     return View(); 
    } 

    public async Task<int> getOnTimeTasks(int id) 
    { 
     return await System.Threading.Tasks.Task.Run(() => db.Tasks.Include(t => t.Job).Where(t => t.Company == User.Identity.Name && t.RepId == id && t.Complete == true && t.CompleteDate <= t.Job.Deadline).ToList().Count); 
    } 

    public async Task<int> getLateTasks(int id) 
    { 
     return await System.Threading.Tasks.Task.Run(() => db.Tasks.Include(t => t.Job).Where(t => t.Company == User.Identity.Name && t.RepId == id && t.Complete == true && t.CompleteDate > t.Job.Deadline).ToList().Count); 
    } 

    public async Task<int> getIncompleteTasks(int id) 
    { 
     return await System.Threading.Tasks.Task.Run(() => db.Tasks.Include(t => t.Job).Where(t => t.Company == User.Identity.Name && t.RepId == id && t.Complete == false).ToList().Count); 
    } 

我甚至不知道這是否會工作(同時運行所有三個任務),所以任何人都可以幫助新手這嗎?

**更新:**我在運行此代碼收到以下錯誤: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.

回答

2

首先,你不應該在ASP.NET使用Task.Run。這樣做會否定async的所有好處。相反,使用自然異步的API,例如EF6的ToListAsync。其次,EF6允許異步API,但只有一次調用(每DbContext)。所以,你可以創建三個不同的數據庫上下文,或者一次只做一個。

你的最終代碼看起來是這樣的:

public async Task<ActionResult> KPI(int id = 0) 
{ 
    ViewData["ontime"] = await getOnTimeTasksAsync(id); 
    ViewData["ictasks"] = await getLateTasksAsync(id); 
    ViewData["incomplete"] = await getIncompleteTasksAsync(id); 
    return View(); 
} 

public Task<int> getOnTimeTasksAsync(int id) 
{ 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 

public Task<int> getLateTasksAsync(int id) 
{ 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 

public Task<int> getIncompleteTasksAsync(int id) 
{ 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 

或者,如果你想同時呼叫:

public async Task<ActionResult> KPI(int id = 0) 
{ 
    var results = await Task.WhenAll(getOnTimeTasksAsync(id), 
     getLateTasksAsync(id), getIncompleteTasksAsync(id)); 
    ViewData["ontime"] = results[0]; 
    ViewData["ictasks"] = results[1]; 
    ViewData["incomplete"] = results[2]; 
    return View(); 
} 

public Task<int> getOnTimeTasksAsync(int id) 
{ 
    var db = new MyDatabaseContext(); 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 

public Task<int> getLateTasksAsync(int id) 
{ 
    var db = new MyDatabaseContext(); 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 

public Task<int> getIncompleteTasksAsync(int id) 
{ 
    var db = new MyDatabaseContext(); 
    return db.Tasks.Include(t => t.Job).Where(...).CountAsync(); 
} 
+0

謝謝您的回覆!這是否仍然允許我同時執行所有三個「getTasks」函數?即使有'等待'? – 2014-10-07 12:31:42

+0

@ barnacle.m:當前的代碼將一次運行一個。如果你想同時運行它們,你需要三種不同的數據庫上下文。 – 2014-10-07 12:36:10

+0

我可以分別爲每個任務實例化上下文,這是否允許我提高性能?這些任務都不依賴於其他任務,因此可以一起執行。 – 2014-10-07 12:38:03