正确的方法来运行这些异步任务?

时间:2014-10-07 11:32:28

标签: c# asp.net-mvc multithreading asynchronous task

我刚开始学习如何处理ASP.NET中的异步任务。我决定尝试在我的一个方法中实现一些异步功能。我需要通过访问数据库获得3个不同的整数,名为ontime,late和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.

1 个答案:

答案 0 :(得分:1)

首先,您不应该在ASP.NET上使用Task.Run。这样做会否定async的所有好处。相反,使用自然异步API,例如EF6&#39; 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();
}