【问题标题】:Use Disposable objects inside Task在 Task 中使用 Disposable 对象
【发布时间】:2020-02-20 00:41:44
【问题描述】:

我正在开发一个 Web 应用程序来处理大量数据并使用这些项目创建一个 .csv 文件。

到目前为止,一切都很好,但是,我发现这个过程并不是很快,所以我决定在任务(线程)中完成所有这些事情。

像这样:

_ = Task.Run(() => {
    try
    {
        LetsGoCrazy(model);
    }
    catch (Exception ex)
    {
        SaveLog(model, "Error dumbass", ex);
    }
});

我的问题是,如何在任务方法中更新我的数据库(实体框架核心)?

因为,它向我显示了这个异常:

System.ObjectDisposedException: '无法访问已处置的对象。此错误的一个常见原因是释放从依赖注入中解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果你使用依赖注入,你应该让依赖注入容器负责处理上下文实例。

我相信它必须有另一种方法来实现这一点,而无需在任务中重新创建实体框架上下文。

【问题讨论】:

  • 你的代码是 fire-and-forget Task,你的代码的其他部分对此一无所知。您只需要awaitTask.Run() 返回的任务。在没有看到你的代码的情况下,仅仅将它放在一个子任务中并不一定会让它运行得更快
  • @MichaelRandall 哈哈我确实喜欢你的类比 :)
  • 奇怪的类比,但有道理兄弟哈哈。我不能让用户等待任务完成。他们最终会收到一封包含该文件的电子邮件
  • 您可能需要某种消息队列服务来处理进程外的LetsGoCrazy

标签: c# multithreading task dispose


【解决方案1】:

你的代码是 一劳永逸 Task,你的代码的其他部分对此一无所知。这意味着应用程序的其余部分无需等待即可继续运行,释放它认为未使用或可能退出的资源。如果您不小心,这很容易在控制台应用程序中发生。对于 web,您可能会发现控制器超出范围以及任何资源。从错误的外观来看,情况似乎如此。

您只需要awaitTask.Run() 返回的任务。

try
{
   await Task.Run(() => LetsGoCrazy(model));
}
catch (SomeException ex)
{
   // ...
}

操作:

到目前为止,一切都很好,但是,我发现这个过程并不是很快,所以我决定在任务(线程)中完成所有这些事情。

在没有看到您的代码的情况下,简单地将其放在子任务中并不一定会让它运行得更快。

依赖注入最佳实践

您应该避免注入 I/O 资源,例如显式数据库连接; WCF 客户端代理;或文件流到客户端代码。这是因为如果连接发生故障,客户端(例如 MVC 控制器)无法重新创建它。

相反,您应该注入一个 provider 对象,当需要连接时客户端调用该对象。与其他与 DI 相关的所有内容一样,对象创建仍然由 DI 系统封装,但它允许在发生故障时动态创建和重新创建对象。

在您的情况下,如果您的 LetsGoCrazy 需要很长时间(例如 > 5 分钟),您可能需要重新创建数据库连接,因为 空闲超时

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-08
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多