【问题标题】:Correct way to run these asynchronous tasks?运行这些异步任务的正确方法?
【发布时间】:2014-12-01 19:44:57
【问题描述】:

我刚刚开始学习如何在 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.

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 感谢您的回复!这是否仍然允许我同时执行所有三个“getTasks”功能?即使有“等待”?
    • @barnacle.m:当前代码将一次运行它们。如果要同时运行它们,则需要三个不同的数据库上下文。
    • 我可以为每个任务分别实例化上下文,这样可以提高性能吗?这些任务都不相互依赖,因此可以一起执行。
    • 如果只有一个物理数据库服务器,那么可能不会,因为只有一个磁盘。如果它是数据库集群或 Azure SQL,那么它可能会提高性能。
    • 最终我希望同时执行许多任务,而不仅仅是数据库调用。作为一个实践问题,我将如何编写该代码以同时将这些值放入 ViewDictionary?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-22
    • 2023-01-14
    • 1970-01-01
    • 2012-06-03
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多