2014-10-07 70 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