TBB并行编程2 _ 性能测试,任务域

2023-12-02 16:10

本文主要是介绍TBB并行编程2 _ 性能测试,任务域,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

性能测试:

#include <tbb/tick_count.h>
#define TICK(x) auto bench_##x = tbb::tick_count::now();
#define TOCK(x) std::cout << #x ": " << (tbb::tick_count::now() - bench_##x).seconds() << "s" << std::endl;#include <iostream>
#include"ticktock.h"
#include <string>
#include <cmath>
#include <vector>
#include <tbb/parallel_for.h>
#include <tbb/blocked_range.h>
#include <tbb/parallel_reduce.h>void test01() {size_t n = 1 << 27;std::vector<float> a(n);TICK(for);tbb::parallel_for(tbb::blocked_range<size_t>(0, n), [&](tbb::blocked_range<size_t> r) {for (size_t i = r.begin(); i < r.end(); i++) {a[i] = std::sin(i);}});TOCK(for);TICK(reduce);float res = tbb::parallel_reduce(tbb::blocked_range<size_t>(0, n), (float)0, [&](tbb::blocked_range<size_t> r, float local_res) {for (size_t i = r.begin(); i < r.end(); i++) {local_res += a[i];}return local_res; }, [](float x, float y) {return x + y;});TOCK(reduce);std::cout << res << std::endl;
}
void test02() {size_t n = 1 << 27;std::vector<float> a(n);TICK(for);for (size_t i = 0; i < n; i++){a[i] += std::sin(i);}TOCK(for);TICK(reduce);float res = 0;for (size_t i = 0; i < n; i++){res += a[i];}TOCK(reduce);std::cout << res << std::endl;
}int main() {test01();std::cout << "------------" << std::endl;test02();
}

通过上面那个时间戳就可以计时,从结果来看显然并行算法耗时更少。

评价一个并行速度通常会用加速比=串行用时÷并行用时

更专业的性能测试框架:Google benchmark

这个我安装了之后一直显示连接不上。。。。我也很奇怪

#include <iostream>
#include <vector>
#include <cmath>
#include <benchmark/benchmark.h>constexpr size_t n = 1<<27;
std::vector<float> a(n);void BM_for(benchmark::State &bm) {for (auto _: bm) {// fill a with sin(i)for (size_t i = 0; i < a.size(); i++) {a[i] = std::sin(i);}}
}
BENCHMARK(BM_for);void BM_reduce(benchmark::State &bm) {for (auto _: bm) {// calculate sum of afloat res = 0;for (size_t i = 0; i < a.size(); i++) {res += a[i];}benchmark::DoNotOptimize(res);}
}
BENCHMARK(BM_reduce);BENCHMARK_MAIN();

 代码是这样的

回更:安装好啦

 总结安装错误:要找到config。

cmake_minimum_required(VERSION 3.10)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE Release)
SET(TBB_DIR "D:\\vsstl\\C_CUDA\\vcpkg-master\\vcpkg-master\\packages\\tbb_x64-windows\\share\\tbb")
SET(benchmark_DIR "D:\\vsstl\\C_CUDA\\vcpkg-master\\vcpkg-master\\packages\\benchmark_x64-windows\\share\\benchmark")
project(main LANGUAGES CXX)add_executable(main main.cpp)#find_package(OpenMP REQUIRED)
#target_link_libraries(main PUBLIC OpenMP::OpenMP_CXX)find_package(TBB REQUIRED)
target_link_libraries(main PUBLIC TBB::tbb)set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Turn off the fking test!")
find_package(benchmark CONFIG REQUIRED)
target_link_libraries(main PUBLIC benchmark::benchmark benchmark::benchmark_main)

任务域与嵌套

#include <iostream>
#include <tbb/parallel_for.h>
#include <tbb/task_arena.h>
#include <vector>
#include <cmath>int main() {size_t n = 1<<26;std::vector<float> a(n);tbb::task_arena ta(4);//可以指定用多少线程ta.execute([&] {tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t i) {a[i] = std::sin(i);});});return 0;
}

也可以用两个for进行嵌套,这样可以解决n比较小,核心没有用光的问题:

tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t i) {tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t j) {a[i * n + j] = std::sin(i) * std::sin(j);});});

但是嵌套会导致死锁问题:

tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t i) {std::lock_guard lck(mtx);tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t j) {a[i * n + j] = std::sin(i) * std::sin(j);});});

这是因为tbb采用的是工作窃取法,就是在线程t1做完自己的工作之后,就会去看别的线程有没有做完工作,如果还有没做完的工作就会从这个线程里将工作取出,放到自己的t1线程里。

因此内部 for 循环有可能“窃取”到另一个外部 for 循环的任务,从而导致 mutex 被重复上锁。

所以为了解决这种问题:

1、用递归锁:

std::recursive_mutex mtx;

2、另外创建一个任务域

 tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t i) {std::lock_guard lck(mtx);tbb::task_arena ta;ta.execute([&] {tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t j) {a[i * n + j] = std::sin(i) * std::sin(j);});});});

3、isolate隔离:

tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t i) {std::lock_guard lck(mtx);tbb::this_task_arena::isolate([&] {tbb::parallel_for((size_t)0, (size_t)n, [&] (size_t j) {a[i * n + j] = std::sin(i) * std::sin(j);});});});

这篇关于TBB并行编程2 _ 性能测试,任务域的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/445962

相关文章

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Spring定时任务之fixedRateString的实现示例

《Spring定时任务之fixedRateString的实现示例》本文主要介绍了Spring定时任务之fixedRateString的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录从毫秒到 Duration:为何要改变?核心:Java.time.Duration.parse

Oracle Scheduler任务故障诊断方法实战指南

《OracleScheduler任务故障诊断方法实战指南》Oracle数据库作为企业级应用中最常用的关系型数据库管理系统之一,偶尔会遇到各种故障和问题,:本文主要介绍OracleSchedul... 目录前言一、故障场景:当定时任务突然“消失”二、基础环境诊断:搭建“全局视角”1. 数据库实例与PDB状态2

Docker多阶段镜像构建与缓存利用性能优化实践指南

《Docker多阶段镜像构建与缓存利用性能优化实践指南》这篇文章将从原理层面深入解析Docker多阶段构建与缓存机制,结合实际项目示例,说明如何有效利用构建缓存,组织镜像层次,最大化提升构建速度并减少... 目录一、技术背景与应用场景二、核心原理深入分析三、关键 dockerfile 解读3.1 Docke

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

Java Stream 并行流简介、使用与注意事项小结

《JavaStream并行流简介、使用与注意事项小结》Java8并行流基于StreamAPI,利用多核CPU提升计算密集型任务效率,但需注意线程安全、顺序不确定及线程池管理,可通过自定义线程池与C... 目录1. 并行流简介​特点:​2. 并行流的简单使用​示例:并行流的基本使用​3. 配合自定义线程池​示

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

Python异步编程之await与asyncio基本用法详解

《Python异步编程之await与asyncio基本用法详解》在Python中,await和asyncio是异步编程的核心工具,用于高效处理I/O密集型任务(如网络请求、文件读写、数据库操作等),接... 目录一、核心概念二、使用场景三、基本用法1. 定义协程2. 运行协程3. 并发执行多个任务四、关键