tbb:concurrent_hash_map:英特尔线程构建模块 (TBB) 的示例代码

2024-03-25

寻找要使用的示例代码tbb::concurrent_hash_map<K,V>来自英特尔线程构建模块 (TBB)。

我可以插入,但我似乎无法读回这些值。

The 英特尔官方文档 https://software.intel.com/en-us/node/506191示例代码方面似乎有些缺乏。

Update

最好的文档位于 Voss 的“Pro TBB:使用线程构建块的 C++ 并行编程”。免费下载这本书 https://www.apress.com/gp/book/9781484243978(这是公共领域)。

忽略英特尔文档。它们本质上是函数签名的集合。


英特尔TBB https://software.intel.com/en-us/tbb是开源的,并且在GitHub https://github.com/intel/tbb:

https://github.com/intel/tbb

为了安装 TBB,我使用了vcpkg https://github.com/Microsoft/vcpkg这是兼容的Linux, Windows and Mac。是的,vcpkg来自微软,但它是100%跨平台、开源的,而且非常流行。

Linux:

./vcpkg search tbb              # Find the package.
./vcpkg install tbb:x64-linux   # Install the package.

Windows:

vcpkg search tbb                # Find the package.
vcpkg install tbb:x64-windows   # Install the package.

Compile:

  • 与任何现代编译器兼容,包括 MSVC、GCC、LLVM、Intel 编译器 (ICC) 等。我使用过CMake for gcc.

还可以下载源代码并将标头和库提取到源代码树中,这也同样有效。

Code.

#include "tbb/concurrent_hash_map.h" // For concurrent hash map.

tbb::concurrent_hash_map<int, string> dict;
typedef tbb::concurrent_hash_map<int, string>::accessor dictAccessor; // See notes on accessor below.   

print("  - Insert key, method 1:\n");   
dict.insert({1,"k1"});
print("    - 1: k1\n");

print("  - Insert key, method 2:\n");
dict.emplace(2,"k2");
print("    - 2: k2\n");

string result;

{
    print("  - Read an existing key:\n");   
    dictAccessor accessor;
    const auto isFound = dict.find(accessor, 2);
    // The accessor functions as:
    // (a) a fine-grained per-key lock (released when it goes out of scope).
    // (b) a method to read the value.
    // (c) a method to insert or update the value.
    if (isFound == true) {
        print("    - {}: {}\n", accessor->first, accessor->second);
    }
}

{
    print("  - Atomically insert or update a key:\n");  
    dictAccessor accessor;
    const auto itemIsNew = dict.insert(accessor, 4);
    // The accessor functions as:
    // (a) a fine-grained per-key lock (released when it goes out of scope).
    // (b) a method to read the value.
    // (c) a method to insert or update the value.
    if (itemIsNew == true) {
        print("    - Insert.\n");
        accessor->second = "k4";
    }
    else {
        print("    - Update.\n");
        accessor->second = accessor->second + "+update";
    }
    print("    - {}: {}\n", accessor->first, accessor->second);     
}

{
    print("  - Atomically insert or update a key:\n");          
    dictAccessor accessor;
    const auto itemIsNew = dict.insert(accessor, 4);
    // The accessor functions as:
    // (a) a fine-grained per-key lock which is released when it goes out of scope.
    // (b) a method to read the value.
    // (c) a method to insert or update the value.
    if (itemIsNew == true) {
        print("    - Insert.\n");
        accessor->second = "k4";
    }
    else {
        print("    - Update.\n");
        accessor->second = accessor->second + "+update";
    }
    print("    - {}: {}\n", accessor->first, accessor->second);     
}

{
    print("  - Read the final state of the key:\n");            
    dictAccessor accessor;
    const auto isFound = dict.find(accessor, 4);
    print("    - {}: {}\n", accessor->first, accessor->second);
}

印刷用途{fmtlib} https://github.com/fmtlib/fmt用于印刷;可以替换为cout <<.

Output:

- Insert key, method 1:
  - 1: k1
- Insert key, method 2:
  - 2: k2
- Read an existing key:
  - 2: k2
- Atomically insert or update a key:
  - Insert.
  - 4: k4
- Atomically insert or update a key:
  - Update.
  - 4: k4+update
- Read the final state of the key:
  - 4: k4+update

其他哈希图

  • See: https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html https://tessil.github.io/2016/08/29/benchmark-hopscotch-map.html
  • See: std::unordered_map。这有一个更标准的 API,并且在很多情况下都是线程安全的,请参阅:unordered_map线程安全 https://stackoverflow.com/questions/9685486/unordered-map-thread-safety。如果可能的话,建议使用它,因为它有一个更简单的 API。
  • 还有concurrent_unordered_map来自英特尔 TBB。它本质上是同一件事,即键/值映射。然而,它的历史要长得多,级别要低得多,而且使用起来更困难。必须提供一个哈希器、一个相等运算符和一个分配器。即使在英特尔官方文档中,也没有任何示例代码。尽管我进行了几个月的偶尔尝试,但我从未成功过。它可能已过时,因为在所述免费书中未提及(它仅涵盖concurrent_hash_map)。不建议。

更新:读取器/写入器锁

实际上有两种访问器,一种是读锁,一种是写锁:

  • const_accessor
  • accessor

如果使用find, use const_accessor这是一个读锁。如果使用insert or erase, use accessor这是一个写锁(即它将等待任何读取完成,并阻止进一步的读取直到完成)。

这实际上相当于读/写锁 https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock,但是在字典中的单个字典键上,而不是整个字典上。

Update

学习曲线的最后部分:对于键写入,在访问器超出范围之前不会发生任何事情。因此,任何锁定都不会超过几个机器指令,可能使用 CAS(比较和交换)。

与数据库相比,访问器的范围就像一个事务。当访问器超出范围时,整个事务将提交到哈希映射。

Update

上面提到的免费书籍在以下章节中提供了精彩的性能技巧:concurrent_hash_map.

结论

这个哈希图的 API 很强大,但有些笨拙。但是,它支持插入/更新时的细粒度、每键锁定。任何锁都仅为少数机器指令而持有,使用CAS https://en.wikipedia.org/wiki/Compare-and-swap。这是其他任何语言的哈希图都无法提供的。建议从std::unordered_map为了简单起见;这是只要两个线程不写入同一个键,线程就是安全的 https://stackoverflow.com/questions/9685486/unordered-map-thread-safety。如果需要极快的性能,可以选择重构,或者在上面编写兼容的包装器[]访问器和insert_or_update().

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

tbb:concurrent_hash_map:英特尔线程构建模块 (TBB) 的示例代码 的相关文章

随机推荐

  • 获取HashMap值的count个数

    使用这里的代码link https stackoverflow com questions 37129625 read and find string from text file将文本文件内容加载到 GUI Map
  • 谷歌分析用户 ID 跟踪

    我通过通用分析实现了 userID 跟踪 ga set uid 我认为我应该能够在报告中看到特定用户 但似乎甚至不可能在任何类型的报告中显示不同的用户 我在分析 API 中也没有找到这个选项 我希望能够跟踪该特定用户创建的事件 是否可以在不
  • 如何重命名 git stash?

    我有一个名称不正确的藏品 我想修正这个名称 使其准确 如何重命名藏匿处 让我们假设您的存储列表如下所示 git stash list stash 0 WIP on master Add some very important feature
  • 如何使用 Astro 获取查询字符串参数

    我正在使用一种名为 Astro 的新技术 https astro build https astro build 构建一个完全静态的服务器端渲染页面 交付零 JS 我有一个带有简单文本输入表单的页面 当用户填写该表单并单击提交按钮时 它会向
  • gpus_ReturnGuiltyForHardwareRestart

    我找到了有关该错误的更多详细信息 它似乎与信息有关 gpus ReturnGuiltyForHardwareRestart google了一下 似乎关于这个bug的信息相当有限 您以前遇到过这种情况并且知道如何解决吗 我认为我有必要更新我所
  • 下载并解压内存中的 gzip 文件?

    我想使用 urllib 下载文件并在保存之前将文件解压缩到内存中 这就是我现在所拥有的 response urllib2 urlopen baseURL filename compressedFile StringIO StringIO c
  • 将会话从模板视图传递到 python 请求 api 调用

    我想使用请求库从 Django TemplateView 进行多个内部 REST API 调用 现在我也想将会话从模板视图传递到 api 调用 考虑到性能 推荐的方法是什么 现在我正在提取cookie从目前的request模板视图中的对象
  • 将 C 字节数组转换为 long long

    我的应用程序中有一个 8 字节数组 其中包含以下数据 00000133339e36a2 该数据代表一个长整型 在写入数据的平台上 在 Mac 上这将是一个长整型 其值为 1319420966562 在实际应用中 这是一组半随机的数据 因此数
  • D3 弧形端部 V 形

    我画了一个arc https github com d3 d3 shape arcs使用 D3 js 默认情况下具有方形末端 var arc d3 arc innerRadius 0 outerRadius 100 startAngle 0
  • 文件包含路径分隔符。

    当我尝试检查特定文件是否存在时 我得到java lang illegalArgumentException File contains a path separator 使用 getFileStreamPath 执行此操作的正确方法是什么
  • Laravel 按字段长度排序

    我想构建一个按特定字段长度对数据进行排序的查询 我需要将此查询重写为 laravel 的 Eloquent ORM SELECT FROM table ORDER BY CHAR LENGTH field 看起来orderByRaw这就是您
  • 有人有使用 OpenCV 和 python 进行描述符提取的示例吗?

    我正在尝试使用 OpenCV 从图像中提取 SURF 描述符 我正在使用 OpenCV 2 4 和 Python 2 7 但很难找到任何提供有关如何使用这些函数的信息的文档 我已经能够使用以下代码来提取特征 但我找不到任何明智的方法来提取描
  • Struts 2下载-如何动态配置文件名?

    我正在开发一个应用程序 人们可以将所需的文件从数据库中提到的位置下载到本地 我正在使用 struts 2 从服务器下载文件 我可以毫无例外地下载该文件 并且运行完美 但是下载的文件具有我在 struts xml 中指定的文件名 我希望它是正
  • `ifstream::readsome` 何时设置 `eofbit`?

    这段代码永远循环 include
  • 如何将 API 参数传递给 GCP 云构建触发器

    我有一大组 GCP Cloud Build 触发器 通过云调度程序调用 所有触发器都运行良好 现在 我想通过外部 API 调用来调用这些触发器 并向它们传递参数值和数量不同的动态参数 我能够通过运行 API 请求来启动触发器 但我发送的 A
  • Spring 3.0 使用 Jackson 消息转换器进行 JSON 响应

    我将我的消息转换器配置为杰克逊的消息转换器 class Foo int x int y 并在控制器中 ResponseBody public Foo method return new Foo 3 4 由此 我期望从服务器返回一个 JSON
  • 如何通过CloudFormation设置EC2实例根卷的标签

    使用 CloudFormation 创建 EC2 实例 但根卷的名称 标签 为空 如何使用CloudFormation进行设置 ec2 instance yml CloudFormation template MyInstance Type
  • 连接到 Tomcat 上的套接字?

    我正在尝试从独立小程序连接到在 tomcat 上运行的 servlet Servlet public void init ServletConfig config throws ServletException super init con
  • Application Insights - 仅获取客户端数据,不获取服务器数据。

    我有一个托管在 Windows Server 2008 上的 ASP Net MVC 4 应用程序 我正在使用 Microsoft Application Insights 它非常适合客户端指标 例如客户端处理时间 自定义事件 用户 会话
  • tbb:concurrent_hash_map:英特尔线程构建模块 (TBB) 的示例代码

    寻找要使用的示例代码tbb concurrent hash map