实例级线程局部存储有哪些优点? [英] What are the advantages of instance-level thread-local storage?

查看:155
本文介绍了实例级线程局部存储有哪些优点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题让我对高级开发框架中的线程本地存储感到疑惑像Java和.NET。



Java有一个 ThreadLocal< T> 类(可能还有其他构造),而.NET有数据插槽,很快就会出现 ThreadLocal< T> 类它自己的。 (它还有 ThreadStaticAttribute ,但我对成员数据的线程局部存储特别感兴趣。)大多数其他现代开发环境为语言或框架级别提供了一种或多种机制。



线程局部存储解决了什么问题,或者线程局部存储在创建单独的对象实例以包含线程本地数据的标准面向对象习惯上提供了哪些优势?换句话说,这是怎么回事:

  //线程本地存储方法 - 使用相同的对象启动200个线程
//每个线程创建任何线程本地数据的副本
ThreadLocalInstance instance = new ThreadLocalInstance();
for(int i = 0; i< 200; i ++){
ThreadStart threadStart = new ThreadStart(instance.DoSomething);
new Thread(threadStart).Start();
}

优于此?

  //正常oo方法,创建200个对象,在每个
上启动一个新线程(int i = 0; i< 200; i ++){
StandardInstance standardInstance = new StandardInstance();
ThreadStart threadStart = new ThreadStart(standardInstance.DoSomething);
new Thread(threadStart).Start();
}

我可以看到使用带有线程本地存储的单个对象可能会略有不同由于分配(和构造)较少,因此内存效率更高,需要更少的处理器资源。还有其他优势吗?

解决方案


线程本地存储解决了什么问题,或者有什么优势呢?线程局部存储提供了标准的面向对象的习惯用法,即创建单独的对象实例以包含线程本地数据?


线程本地存储允许您为每个正在运行的线程提供一个类的唯一实例,这在尝试使用非线程安全类时非常有用,或者在尝试避免由于共享状态而可能发生的同步要求时。



至于优势与您的示例 - 如果您正在生成单个线程,那么使用线程本地存储而不是传入实例几乎没有优势。 ThreadLocal< T> 和类似的构造在使用ThreadPool(直接或间接)工作时变得非常有价值。



<例如,我最近有一个特定的过程,我们使用.NET中的新任务并行库进行一些非常繁重的计算。执行的计算的某些部分可以被缓存,并且如果缓存包含特定匹配,我们可以在处理一个元素时节​​省相当多的时间。但是,缓存的信息具有较高的内存要求,因此我们不希望缓存超过上一个处理步骤。



但是,尝试跨线程共享此缓存是有问题的。为了做到这一点,我们必须同步对它的访问,并在我们的类中添加一些额外的检查,以使它们的线程安全。



而不是为此,我重写了算法,允许每个线程在 ThreadLocal< T> 中维护自己的私有缓存。这允许每个线程维护自己的私有缓存。由于TPL使用的分区方案倾向于将元素块保持在一起,每个线程的本地缓存倾向于包含它所需的适当值。



这消除了同步问题,但是也让我们保持缓存。在这种情况下,整体收益非常大。



有关更具体的示例,请查看我在使用TPL汇总。在内部,只要您使用 ThreadLocal< TLocal> (VS.100).aspxrel =noreferrer>保持本地状态的ForEach重载(以及 Parallel.For< TLocal> 方法) 。这是每个线程保持本地状态分开以避免锁定的方式。


This question led me to wonder about thread-local storage in high-level development frameworks like Java and .NET.

Java has a ThreadLocal<T> class (and perhaps other constructs), while .NET has data slots, and soon a ThreadLocal<T> class of its own. (It also has the ThreadStaticAttribute, but I'm particularly interested in thread-local storage for member data.) Most other modern development environments provide one or more mechanisms for it, either at the language or framework level.

What problems does thread-local storage solve, or what advantages does thread-local storage provide over the standard object-oriented idiom of creating separate object instances to contain thread-local data? In other words, how is this:

// Thread local storage approach - start 200 threads using the same object
// Each thread creates a copy of any thread-local data
ThreadLocalInstance instance = new ThreadLocalInstance();
for(int i=0; i < 200; i++) {
    ThreadStart threadStart = new ThreadStart(instance.DoSomething);
    new Thread(threadStart).Start();
}

Superior to this?

// Normal oo approach, create 200 objects, start a new thread on each
for(int i=0; i < 200; i++) {
    StandardInstance standardInstance = new StandardInstance();
    ThreadStart threadStart = new ThreadStart(standardInstance.DoSomething);      
    new Thread(threadStart).Start();
}

I can see that using a single object with thread-local storage could be slightly more memory-efficient and require fewer processor resources due to fewer allocations (and constructions). Are there other advantages?

解决方案

What problems does thread-local storage solve, or what advantages does thread-local storage provide over the standard object-oriented idiom of creating separate object instances to contain thread-local data?

Thread local storage allows you to provide each running thread with a unique instance of a class, which is very valuable when trying to work with non-threadsafe classes, or when trying to avoid synchronization requirements that can occur due to shared state.

As for the advantage vs. your example - if you are spawning a single thread, there is little or no advantage to using thread local storage over passing in an instance. ThreadLocal<T> and similar constructs become incredibly valuable, however, when working (directly or indirectly) with a ThreadPool.

For example, I have a specific process I worked on recently, where we are doing some very heavy computation using the new Task Parallel Library in .NET. Certain portions of the computations performed can be cached, and if the cache contains a specific match, we can shave off quite a bit of time when processing one element. However, the cached info had a high memory requirement, so we didn't want to cache more than the last processing step.

However, trying to share this cache across threads is problematic. In order to do so, we'd have to synchronize the access to it, and also add some extra checks inside of our class to make them thread safe.

Instead of doing this, I rewrote the algorithm to allow each thread to maintain its own private cache in a ThreadLocal<T>. This allows the threads to each maintain their own, private cache. Since the partitioning scheme the TPL uses tends to keep blocks of elements together, each thread's local cache tended to contain the appropriate values it required.

This eliminated the synchronization issues, but also allowed us to keep our caching in place. The overall benefit was quite large, in this situation.

For a more concrete example, take a look at this blog post I wrote on aggregation using the TPL. Internally, the Parallel class uses a ThreadLocal<TLocal> whenever you use the ForEach overload that keeps local state (and the Parallel.For<TLocal> methods, too). This is how the local state is kept separate per thread to avoid locking.

这篇关于实例级线程局部存储有哪些优点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆