【问题标题】:ThreadLocal and Task线程本地和任务
【发布时间】:2016-07-04 19:16:45
【问题描述】:

我使用静态 ThreadLocal 来缓存一些重量级对象。考虑以下代码:

class MatchItemFinder
{
    private static ThreadLocal<PaddedImage> tempImage;
    MatchItemFinder()
    {
        if(tempImage==null) 
            tempImage = new ThreadLocal<PaddedImage>(
            () => new PaddedImage(patchSize, patchSize));
    }
    internal void DoSomething(){
        //Do something with tempImage.Value
    }
}

从多个任务并行库线程调用 DoSomething() 时,何时创建每个实例?我的意思是显然线程被重用所以我的 tempImage 是每次创建线程或每次重用线程时创建的?

从设计的角度来看,您认为这种缓存是一个很好的决定,还是有更好的策略来以线程安全的方式缓存大对象?

我正在使用 .Net 4。

【问题讨论】:

  • 缓存的目标是什么?您真的希望每个线程都有自己的大对象副本吗?或者您是否真的希望以线程安全的方式与所有线程共享一个 single 大对象?如果是后者,请查看 Lazy 类。
  • @sstan 你问对了问题。我真的不想拥有 250 个大对象实例。理想的情况是实例数量与在特定时间实际上在 tempImages 上执行某些操作的并发线程数一样少,例如对应于 8 个超线程内核的 8 个实例。 Lazy 没有完成这项工作,因为它与初始化无关。大对象是由 DoSomething() 操作的临时图像,因此单个实​​例在这里不起作用。

标签: c# multithreading


【解决方案1】:

线程局部变量不与 TPL 或线程池合作。它们是基于Thread 的。当任何 TPL 库函数重用线程时,您的线程局部变量将被重用。

从设计的角度来看,您认为这种缓存是一个很好的决定,还是有更好的策略来以线程安全的方式缓存大对象?

如果您的缓存项是不可变的,则不需要线程本地项。使用全局缓存。

【讨论】:

  • 它们的对象不是不可变的,它们在 DoSomething 中被操纵,所以应该存在单独的实例
  • 也许你可以使用一个ObjectPool,让线程合作检出并返回实例?
  • 似乎是唯一合理的解决方案。我希望能有一些不那么复杂的东西
猜你喜欢
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-25
  • 2010-12-29
相关资源
最近更新 更多