【问题标题】:.NET TPL lambdas and closures - will this code work.NET TPL lambdas 和闭包 - 此代码是否有效
【发布时间】:2011-05-31 07:17:00
【问题描述】:

所以我正在尝试使用 .NET 4.0 中的 TPL 功能并编写一些类似这样的代码(不要笑):

/// <summary>Fetches a thread along with its posts.  Increments the thread viewed counter.</summary>
public Thread ViewThread(int threadId)
{
   // Get the thread along with the posts
   Thread thread = this.Context.Threads.Include(t => t.Posts)
       .FirstOrDefault(t => t.ThreadID == threadId);

   // Increment viewed counter
   thread.NumViews++;
   Task.Factory.StartNew(() =>
   {
       try {
           this.Context.SaveChanges();
       }
       catch (Exception ex) {
           this.Logger.Error("Error viewing thread " + thread.Title, ex);
       }

       this.Logger.DebugFormat(@"Thread ""{0}"" viewed and incremented.", thread.Title);
   });

   return thread;
}

所以我对 lambda 的直接关注是 this.Context(我的实体框架数据上下文成员)、this.Logger(记录器成员)和线程(在记录器调用中使用)。通常在 QueueUserWorkItem() 天,我认为这些需要作为状态对象的一部分传递给委托。关闭会不会让我不再需要这样做?

另一个问题是该例程所在的类型实现了 IDisposable,因此位于 using 语句中。所以如果我做类似...

using (var bl = new ThreadBL()) {
            t = bl.ViewThread(threadId);
        }

...我要在 dispose() 调用和 TPL 开始调用我的 lambda 之间进行竞争吗?

目前我看到上下文将数据保存回我的数据库,但没有记录 - 也没有例外。这可能是我的配置问题,但这段代码感觉很奇怪。我不想在其他线程中有未处理的异常。欢迎任何意见!

【问题讨论】:

    标签: multithreading c#-4.0 closures task-parallel-library


    【解决方案1】:

    至于你关于闭包的问题,​​是的,这正是闭包的意义所在。您不必担心传递状态,而是从任何外部上下文中为您捕获并复制到编译器提供的类中,该类也是定义闭包方法的地方。编译器在这里做了很多魔法,让你的生活变得简单。如果您想了解更多,我强烈建议您深入学习 Jon Skeet 的 C#。关于闭包的章节其实是available here

    至于您的具体实现,它主要不适用于您提到的确切问题:任务将安排在ViewThread 的末尾,但可能在您的ThreadBL 实例被处理之前不会执行。

    【讨论】:

    • 我已经跳过了这个实现,但为了将来参考 - 如果我不处理 ThreadBL 实例,我是否可以保证 GC 不会完成实例?我想我要问的是:就运行时和垃圾收集而言,闭包是否算作对您的对象的引用?听起来像,但我不确定我是否理解 100% 感谢 Skeet 文章的链接。
    • 是的,因为它是您在闭包中引用的“this”,它将被闭包“捕获”,并且在这种情况下会保留引用。问题是在这种情况下您将如何处理 ThreadBL?这将违背正常的工作单元模式。通常最好不要在 BL 类型类中嵌套线程/任务逻辑,让应用程序使用它们的方式来决定何时/如何线程化工作。
    • Re:处理对象:那么您如何建议让查看线程的行为也增加查看的计数器(无需等待碰撞)?在我看来,这似乎是“业务逻辑”方法的理想案例……我不想打扰客户,因为它应该记住每次显示线程时都要增加一个计数器。顺便说一句,你已经回答了原来的问题,谢谢。
    • 现在的设计方式,你不能真正做到干净利落。您的 ThreadBL 似乎在某种程度上是为工作单元模式设计的,但您在其方法中提交工作,这会破坏该模式。您需要做的是停止在您的 ThreadBL 方法中调用 SaveChanges,并实际在 ThreadBL 本身上公开一个 SaveChanges,以便所有者(应用程序)可以决定如何/何时保存更改。完成后,应用程序可以同步地对 ViewThread 进行所有调用,然后它可以将更改排队保存到 Task 并在该任务完成时处理 ThreadBL。
    猜你喜欢
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2016-12-13
    • 1970-01-01
    • 2017-11-08
    • 2018-08-08
    相关资源
    最近更新 更多