运行这些异步任务的正确方式

本文关键字:方式 任务 异步 运行 | 更新日期: 2023-09-27 18:25:57

我刚刚开始学习如何在ASP.NET中处理异步任务。我决定尝试在我的一个方法中实现一些异步功能。我需要通过访问数据库获得3个不同的整数,分别命名为ontime、late和incc。这一切都可以同时完成,因为方法中的其他内容都不依赖于这些调用的输出。阅读后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);
    }

我甚至不确定这是否可行(同时运行所有三项任务),所以有人能帮助新手吗?

**更新:**我在运行此代码时收到以下错误: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.

运行这些异步任务的正确方式

首先,不应该在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();
}