ThreadCachedInt
folly/ThreadCachedInt.h
High-performance atomic increment using thread caching.
folly/ThreadCachedInt.h introduces a integer class designed for high performance increments from multiple threads simultaneously without loss of precision. It has two read modes, readFast gives a potentially stale value with one load, and readFull gives the exact value, but is much slower, as discussed below.
Performance
Increment performance is up to 10x greater than std::atomic_fetch_add in high contention environments. See folly/test/ThreadCachedIntTest.h for more comprehensive benchmarks.
readFast is as fast as a single load.
readFull, on the other hand, requires acquiring a mutex and iterating through a list to accumulate the values of all the thread local counters, so is significantly slower than readFast.
Usage
Create an instance and increment it with increment or the operator overloads. Read the value with readFast for quick, potentially stale data, or readFull for a more expensive but precise result. There are additional convenience functions as well, such as set.
ThreadCachedInt<int64_t> val;
EXPECT_EQ(, val.readFast());
++val; // increment in thread local counter only
EXPECT_EQ(, val.readFast()); // increment has not been flushed
EXPECT_EQ(, val.readFull()); // accumulates all thread local counters
val.set();
EXPECT_EQ(, val.readFast());
EXPECT_EQ(, val.readFull());
Implementation
folly::ThreadCachedInt uses folly::ThreadLocal to store thread specific objects that each have a local counter. When incrementing, the thread local instance is incremented. If the local counter passes the cache size, the value is flushed to the global counter with an atomic increment. It is this global counter that is read with readFast via a simple load, but will not count any of the updates that haven't been flushed.
In order to read the exact value, ThreadCachedInt uses the extended readAllThreads() API of folly::ThreadLocal to iterate through all the references to all the associated thread local object instances. This currently requires acquiring a global mutex and iterating through the references, accumulating the counters along with the global counter. This also means that the first use of the object from a new thread will acquire the mutex in order to insert the thread local reference into the list. By default, there is one global mutex per integer type used in ThreadCachedInt. If you plan on using a lot of ThreadCachedInts in your application, considering breaking up the global mutex by introducing additional Tag template parameters.
set simply sets the global counter value, and marks all the thread local instances as needing to be reset. When iterating with readFull, thread local counters that have been marked as reset are skipped. When incrementing, thread local counters marked for reset are set to zero and unmarked for reset.
Upon destruction, thread local counters are flushed to the parent so that counts are not lost after increments in temporary threads. This requires grabbing the global mutex to make sure the parent itself wasn't destroyed in another thread already.
Alternate Implementations
There are of course many ways to skin a cat, and you may notice there is a partial alternate implementation in folly/test/ThreadCachedIntTest.cpp that provides similar performance. ShardedAtomicInt simply uses an array ofstd::atomic<int64_t>'s and hashes threads across them to do low-contention atomic increments, and readFull just sums up all the ints.
This sounds great, but in order to get the contention low enough to get similar performance as ThreadCachedInt with 24 threads, ShardedAtomicInt needs about 2000 ints to hash across. This uses about 20x more memory, and the lock-freereadFull has to sum up all 2048 ints, which ends up being a about 50x slower than ThreadCachedInt in low contention situations, which is hopefully the common case since it's designed for high-write, low read access patterns. Performance of readFull is about the same speed as ThreadCachedInt in high contention environments.
Depending on the operating conditions, it may make more sense to use one implementation over the other. For example, a lower contention environment will probably be able to use a ShardedAtomicInt with a much smaller array without hurting performance, while improving memory consumption and perf of readFull.
ThreadCachedInt的更多相关文章
- folly学习心得(转)
原文地址: https://www.cnblogs.com/Leo_wl/archive/2012/06/27/2566346.html 阅读目录 学习代码库的一般步骤 folly库的学习心得 ...
- Folly: Facebook Open-source Library Readme.md 和 Overview.md(感觉包含的东西并不多,还是Boost更有用)
folly/ For a high level overview see the README Components Below is a list of (some) Folly component ...
随机推荐
- UVA-10816 Travel in Desert (最小瓶颈最短路)
题目大意:给一张无向图,图中的每条边都有两个权值,长度d和热度r.找出从起点到终点的一条最大热度最小的路径,如果这样的路径有多条,选择一个最短的. 题目分析:如果只考虑最小的最大热度,那么本题就是一个 ...
- 给 C# Expression Evaluator 增加中文变量名支持
由于一些特殊的原因,我的Expression里面需要支持中文变量名,但是C# Expression Evaluator会提示错误,在他的HelperMethods.IsAlpha()里面加上这么一段就 ...
- vue 子组件传递数据跟父组件
子组件 <body> <div v-on:click="test"></div> <script> export default { ...
- 在ubuntu16中部署Django使用memcached作为缓存
Django支持很多缓存系统,如 文件系统缓存. 数据库缓存. 内存缓存(Memcached),其中,Memcached是最快的,没有之一,是绝配.因为所有的缓存数据都放在内存,没有了IO延迟,也没有 ...
- plsql的快速生成sql语句设置
单 单击tool(工具)->的preferences(首选项) ,进入到首选项页面 在点击user interface 的editor下的autoreplace 的edit按钮 ...
- java静态代理和动态代理(一)
代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题. 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为 ...
- 从开发者的角度分析iOS应如何省电
从开发者的角度分析iOS应如何省电 说明 网上关于iPhone如何省电的文章很多.但是基本没有讲原理.而在生活中,很多人在使用iPhone中有着明显的错误的省电习惯. 本文从iOS开发者的角度,对iO ...
- yaf 整理札记
由于yaf只是一个web框架,只负责处理web请求之类的基本功能,相当简洁,连db库都没有.于是试着把zend 2.2的db库,form库,validator库与yaf结合,写了一个demo.因为ze ...
- 如何检测MySQL中建立的索引是否生效
使用方法,在select语句前加上explain就可以了: EXPLAIN SELECT surname,first_name form a,b WHERE a.id=b.id EXPLAIN列的解释 ...
- windows常用DLL及作用
Kernel.dll:内存,硬盘灯硬件管理的相关函数. gdi32.dll:图形显示相关函数(LoadImage,GetPixel,StretchBlt,Ellipse). user32.dll:wi ...