CUDA 中Thrust exclusive_scan使用详解

1. 基本概念

  • Thrust 是 NVIDIA CUDA 提供的类似 C++ STL 的并行算法库。

  • Scan (前缀和):给定数组 [a0, a1, a2, ...],产生前缀和序列。

  • Exclusive Scan (排他前缀和)

    • 输出位置 i 存放的是输入数组中 0 到 i-1 的累积结果
    • 换句话说,结果向右错位一格,首位放初始值

公式:

output[0] = init
output[i] = input[0] ⊕ input[1] ⊕ ... ⊕ input[i-1],  (i > 0)

其中 是二元操作符(默认是加法)。

inclusive_scan 的区别:

  • inclusive:包含当前位置 → output[i] = input[0] + ... + input[i]
  • exclusive:不包含当前位置 → output[i] = input[0] + ... + input[i-1]

2. 函数原型

// 版本 1:默认加法
template <typename InputIterator, typename OutputIterator>
OutputIterator exclusive_scan(InputIterator first, InputIterator last, OutputIterator result);// 版本 2:指定初始值
template <typename InputIterator, typename OutputIterator, typename T>
OutputIterator exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, T init);// 版本 3:指定二元运算符
template <typename InputIterator, typename OutputIterator, typename T, typename BinaryFunction>
OutputIterator exclusive_scan(InputIterator first, InputIterator last, OutputIterator result, T init, BinaryFunction binary_op);

参数说明:

  • first, last:输入区间
  • result:输出区间
  • init:初始值(默认 0)
  • binary_op:二元操作(默认 thrust::plus<T>()

返回值:输出迭代器(即 result + (last - first)


3. 示例代码

🔹 默认加法 + 默认初始值

#include <thrust/scan.h>
#include <thrust/device_vector.h>
#include <iostream>int main() {thrust::device_vector<int> d_in{1, 2, 3, 4};thrust::device_vector<int> d_out(4);thrust::exclusive_scan(d_in.begin(), d_in.end(), d_out.begin());// 输出:0 1 3 6for (int x : d_out) std::cout << x << " ";
}

解释:

  • 输入 [1, 2, 3, 4]
  • 输出 [0, 1, 3, 6]

指定初始值

thrust::exclusive_scan(d_in.begin(), d_in.end(), d_out.begin(), 10);

输入 [1, 2, 3, 4],结果 [10, 11, 13, 16]


自定义运算符(乘法)

struct multiply
{__host__ __device__ int operator()(const int &a, const int &b) const {return a * b;}
};thrust::exclusive_scan(d_in.begin(), d_in.end(), d_out.begin(), 1, multiply());

输入 [1, 2, 3, 4],结果 [1, 1, 2, 6]


4. 内部实现原理

  • exclusive_scan 在 GPU 上通常使用 并行前缀和算法(Blelloch Scan):

    1. 上行阶段(reduce):树形归约,计算部分和。
    2. 下行阶段(down-sweep):回传累积和,得到 exclusive 结果。
  • 复杂度:O(n)

  • 并行化效率:在 CUDA 中可利用 warp shuffle / shared memory 优化。


5. 常见应用

  1. 数组索引计算:比如稀疏矩阵非零元素位置。
  2. 并行 compact/filter:布尔标记数组 → 前缀和 → 计算输出位置。
  3. 动态内存分配:统计每个线程写入位置。
  4. 图算法:CSR 格式构建、邻接表索引。

6. 易错点

exclusive vs inclusive:结果差一个位置,常见 bug。
初始值:没设置时默认 0,很多人误以为会报错。
in-place 使用:输入和输出可以是同一个 vector(安全)。
自定义运算符:必须满足结合律(associative),否则结果不稳定。


7. 性能优化

  • exclusive_scan 已由 Thrust 内部优化,适合中大规模数组。
  • 小规模数组时,CPU std::exclusive_scan 可能更快。
  • 多次调用时建议 预分配 device_vector,避免反复分配内存。

8、 exclusive_scan vs inclusive_scan 对比表

特性exclusive_scaninclusive_scan
定义输出位置 i 是输入 [0..i-1] 的累积和,当前位置 不包含输出位置 i 是输入 [0..i] 的累积和,当前位置 包含
首元素结果 output[0] = init(默认 0)结果 output[0] = input[0]
数学表达式out[i] = init ⊕ in[0] ⊕ ... ⊕ in[i-1]out[i] = in[0] ⊕ in[1] ⊕ ... ⊕ in[i]
输入 [1, 2, 3, 4],init=0输出 [0, 1, 3, 6]输出 [1, 3, 6, 10]
典型用途计算 索引偏移、数组 compaction、CSR 图结构直接得到前缀累计量,例如直方图累计、累积分布函数 (CDF)

9、典型应用场景代码

1️、数组索引偏移(exclusive_scan)

常见于 稀疏矩阵 / 图的 CSR 格式构建

#include <thrust/scan.h>
#include <thrust/device_vector.h>
#include <iostream>int main() {thrust::device_vector<int> flags{1, 0, 1, 1, 0};thrust::device_vector<int> indices(flags.size());// exclusive_scan:计算每个位置在输出数组的起始索引thrust::exclusive_scan(flags.begin(), flags.end(), indices.begin());// 输出: 0 1 1 2 3for (int x : indices) std::cout << x << " ";
}

解释:

  • flags 表示某位置是否有效
  • exclusive_scan 得到每个有效元素在输出数组中的索引位置

2️、数组 compaction(exclusive_scan + scatter)

保留布尔条件为真的元素,常用于 过滤数据

#include <thrust/scan.h>
#include <thrust/copy.h>
#include <thrust/device_vector.h>
#include <iostream>int main() {thrust::device_vector<int> data{3, 7, 0, 4, 9};thrust::device_vector<int> flags{1, 0, 1, 0, 1};thrust::device_vector<int> indices(flags.size());thrust::device_vector<int> result(3); // 预估有效数量thrust::exclusive_scan(flags.begin(), flags.end(), indices.begin());// 根据 flags 把有效元素写入结果数组for (int i = 0; i < flags.size(); i++) {if (flags[i]) result[indices[i]] = data[i];}// 输出: 3 0 9for (int x : result) std::cout << x << " ";
}

3️、累积分布函数 CDF(inclusive_scan)

常用于 直方图后处理

#include <thrust/scan.h>
#include <thrust/device_vector.h>
#include <iostream>int main() {thrust::device_vector<int> hist{2, 3, 5, 4};thrust::device_vector<int> cdf(hist.size());thrust::inclusive_scan(hist.begin(), hist.end(), cdf.begin());// 输出: 2 5 10 14for (int x : cdf) std::cout << x << " ";
}

解释:

  • 输入直方图 [2,3,5,4]
  • inclusive_scan 得到累积分布 [2,5,10,14]

4️、并行前缀乘积(inclusive_scan with multiply)

用于 概率链式计算

struct multiply {__host__ __device__ float operator()(float a, float b) const {return a * b;}
};thrust::device_vector<float> probs{0.9, 0.8, 0.7, 0.6};
thrust::device_vector<float> cumprod(probs.size());thrust::inclusive_scan(probs.begin(), probs.end(), cumprod.begin(), multiply());// 输入: 0.9 0.8 0.7 0.6
// 输出: 0.9 0.72 0.504 0.3024

10、 总结

  • exclusive_scan:计算“排他前缀和”,结果右移一位,首位为初始值。
  • 三种重载:默认 / 指定 init / 指定 init + 运算符。
  • 应用广泛:稀疏矩阵、图算法、并行 compaction。
  • 注意事项:exclusive vs inclusive,init 值,自定义运算符必须结合律。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/99230.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/99230.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux -- 信号【上】

目录 一、信号的引入 1、信号概念 2、signal函数 普通标准信号详解表 3、前台/后台进程 3.1 概念 3.2 查看后台进程 3.3 后台进程拉回前台 3.4 终止后台进程 3.5 暂停前台进程 3.6 回复运行后台进程 4、发信号的本质 二、信号的产生 1、终端按键 2、系统调用 2…

Altium Designer(AD)自定义PCB外观颜色

目录 1视图设置界面介绍 2PCB阻焊层颜色设置 2.1进入视图设置界面 2.2阻焊层颜色设置 2.3顶层和底层阻焊层颜色设置 2.4顶层阻焊层试图效果 2.5底层阻焊层试图效果 3设置PCB丝印颜色设置 3.1找到丝印设置选项 3.2设置顶层和底层丝印颜色 3.3顶层丝印 3.4底层丝印 4…

5天改造,节能50%!冷能改造如何实现“不停产节能”?

你有没有发现一个现象&#xff1f;很多工厂老板一提到节能改造&#xff0c;第一反应就是摇头。不是不想省电费&#xff0c;而是怕停产。停产一天损失几十万&#xff0c;改造周期动辄几个月&#xff0c;这账怎么算都不划算。但如果我告诉你&#xff0c;有一种改造方式&#xff0…

【Flink】窗口

目录窗口窗口的概念窗口的分类滚动窗口&#xff08;Tumbling Windows&#xff09;滑动窗口&#xff08;Sliding Windows&#xff09;会话窗口&#xff08;Session Windows&#xff09;全局窗口&#xff08;Global Windows&#xff09;窗口API概览窗口函数增量聚合函数ReduceFun…

攻击路径(4):API安全风险导致敏感数据泄漏

本文是《攻防演练 | JS泄露到主机失陷[1]》的学习笔记&#xff0c;欢迎大家阅读原文。攻击路径通过未授权访问攻击获取敏感数据通过SQL注入攻击获取服务器权限通过凭据访问攻击获取数据库权限和敏感数据和应用权限安全风险与加固措施通过未授权访问攻击获取敏感数据、通过SQL注…

机器学习面试题:请介绍一下你理解的集成学习算法

集成学习&#xff08;Ensemble Learning&#xff09;的核心思想是“集思广益”&#xff0c;它通过构建并结合多个基学习器&#xff08;Base Learner&#xff09;来完成学习任务&#xff0c;从而获得比单一学习器更显著优越的泛化性能。俗话说&#xff0c;“三个臭皮匠&#xff…

Invalid bound statement (not found): com.XXX.XXx.service.xxx无法执行service

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.xxx.service.CitytownService.selectCitytown 出现无法加载sevice层的时候&#xff0c;如下图所示1&#xff0c;处理方法是&#xff0c;先看下注解MapperScan内的包地址&#xff0c…

泛型(Generics)what why when【前端TS】

我总是提醒自己一定要严谨严谨严谨 目录TypeScript 泛型 (Generics)1. 什么是泛型&#xff1f;2. 为什么需要泛型&#xff1f;3. 泛型常见用法3.1 函数泛型3.2 接口泛型3.3 类泛型3.4 泛型约束3.5 泛型默认值3.6 多个泛型参数4. 泛型应用场景TypeScript 泛型 (Generics) 1. 什…

分布式协议与算法实战-协议和算法篇

05丨Paxos算法&#xff08;一&#xff09;&#xff1a;如何在多个节点间确定某变量的值? 提到分布式算法&#xff0c;就不得不提 Paxos 算法&#xff0c;在过去几十年里&#xff0c;它基本上是分布式共识的代名词&#xff0c;因为当前最常用的一批共识算法都是基于它改进的。比…

9.13 9.15 JavaWeb(事务管理、AOP P172-P182)

事务管理事务概念事务是一组操作的集合&#xff0c;是一个不可分割的工作单位&#xff0c;这些操作要么同时成功&#xff0c;要么同时失败操作开启事务&#xff08;一组操作开始前&#xff0c;开启事务&#xff09;&#xff1a;start transaction / begin提交事务&#xff08;这…

检索融合方法- Distribution-Based Score Fusion (DBSF)

在信息检索&#xff08;IR&#xff09;、推荐系统和多模态检索中&#xff0c;我们常常需要融合来自多个检索器或模型的结果。不同检索器可能对同一文档打出的分数差异很大&#xff0c;如果直接简单加权&#xff0c;很容易出现某个检索器“主导融合结果”的情况。 Distribution…

Oracle体系结构-归档日志文件(Archive Log Files)

核心概念&#xff1a;什么是归档日志文件&#xff1f; 定义&#xff1a; 归档日志文件&#xff08;Archive Log Files&#xff09;是在线重做日志文件&#xff08;Online Redo Log Files&#xff09;在被覆盖之前的一个完整副本。它们由 Oracle 的后台进程 ARCn&#xff08;归档…

GoogLeNet实战:用PyTorch实现经典Inception模块

配套笔记&讲解视频&#xff0c;点击文末名片获取研究背景&#xff08;Background&#xff09; 1.1 领域现状&#xff08;大环境与挑战&#xff09; 想象一下&#xff0c;你和朋友们在看一大堆照片——猫、狗、汽车、蛋糕&#xff0c;大家要把每张照片贴上标签。几年前&…

【开题答辩全过程】以 “旧书驿站”微信小程序的设计与开发为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

【办公类-112-01】20250912家园每周沟通指导(Deepseek扩写完善+Python模拟点击鼠标自动发送给家长微信)

背景需求 孩子刚上小班,家长比较关心孩子情况(情绪、社交、吃饭等) 所以我每周五晚上和家长沟通一下孩子的情况。 操作流程 第一周(9月5日)是“适应周”,我添加了所有孩子的一位家长的微信号 23份全部是手打,足足写了4个小时。第一周案例多,所以写了很多,措辞酝酿后…

Spark专题-第一部分:Spark 核心概述(1)-Spark 是什么?

众所周知&#xff0c;教学文档总该以理论部分作为开篇&#xff0c;于是我们这篇Spark专题同样会以一堆理论和专有名词开始&#xff0c;笔者会尽可能的让专业词汇通俗易懂 第一部分&#xff1a;Spark 核心概述 Spark 是什么&#xff1f; 1. 大数据时代的"超级赛车"…

从零到一上手 Protocol Buffers用 C# 打造可演进的通讯录

一、为什么是 Protobuf&#xff08;而不是 XML/自定义字符串/.NET 二进制序列化&#xff09; 在需要把结构化对象持久化或跨进程/跨语言传输时&#xff0c;常见方案各有痛点&#xff1a; BinaryFormatter 等 .NET 二进制序列化&#xff1a;对类型签名与版本极其脆弱、体积偏大&…

计算机网络(三)网络层

三、网络层网络层是五层模型中的第三层&#xff0c;位于数据链路层和传输层之间。它的核心任务是实现数据包在不同网络之间&#xff08;跨网络&#xff09;的逻辑传输。网络层的数据传输单位是数据报&#xff08;Datagram&#xff09;或数据包&#xff08;Packet&#xff09;。…

互联网大厂Java面试实录:从基础到微服务全栈技术答疑

互联网大厂Java面试实录&#xff1a;从基础到微服务全栈技术答疑 本文以电商场景为背景&#xff0c;展现一场互联网大厂Java开发职位的面试过程。严肃的面试官与搞笑的水货程序员谢飞机展开三轮技术问答&#xff0c;涵盖Java SE、Spring Boot、数据库、微服务、安全以及CI/CD等…

StringBuilder 深度解析:数据结构与扩容机制的底层细节

文章目录 前言 一、数据结构&#xff1a;不止是简单的字符数组 1. 核心成员变量&#xff08;定义在 AbstractStringBuilder 中&#xff09; 2. 构造器与初始容量 二、扩容机制&#xff1a;从 "不够用" 到 "换大容器" 的全过程 步骤 1&#xff1a;计算…