2014-10-07 2 views
0

Я только начал изучать, как бороться с асинхронными задачами в ASP.NET. Я решил попробовать и реализовать некоторые асинхронные функции в одном из моих методов. Мне нужно получить 3 разных целых числа, названных ontime, late и incomp, обратившись к базе данных. Это можно сделать в то же самое время, поскольку ничто другое в методе не зависит от вывода этих вызовов. После прочтения http://msdn.microsoft.com/en-us/library/hh524395.aspx и http://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); 
    } 

Я даже не уверен, если это будет работать (выполнять все три задачи одновременно), так что может кто-нибудь помочь новичку с этим?

** UPDATE ** я получил следующее сообщение об ошибке при выполнении этого кода: 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

Во-первых, вы не должны использовать Task.Run на ASP.NET. Это отрицает все преимущества async. Вместо этого используйте естественно-асинхронные API, такие как EF6's ToListAsync.

Во-вторых, EF6 разрешает асинхронные API, но только один звонок за один раз (за DbContext). Таким образом, вы можете создать три разных контекста db или просто сделать их по одному.

Ваш окончательный код может выглядеть следующим образом:

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»? Даже с «ожиданием»? –

+0

@ barnacle.m: текущий код будет запускать их по одному. Если вы хотите запустить их одновременно, вам понадобятся три разных контекста базы данных. –

+0

Я могу создать контекст отдельно для каждой задачи, позволил бы мне улучшить производительность? Ни одна из этих задач не зависит друг от друга, поэтому они могут выполняться вместе. –

Смежные вопросы