C#多维数组不同读取方式的性能差异

news2024/11/14 18:46:10

背景

近来在优化一个图像显示程序,图像数据存储于一个3维数组data[x,y,z]中,三维数组为一张张图片数据的叠加而来,其中x为图片的张数,y为图片行,Z为图片的列,也就是说这个三维数组存储的为一系列图片的数据集,整个数据集构成了一个现实中的物体(其实就是一个人的某部位CT扫描结果)。

yoz为主视图,xoz为俯视图,xoy为左视图。

在进行数组读取时,发现如果X固定,YZ为变量获取一张图片时(Y从小到大,Z从小到大),整个获取像素的函数运行时间一般为3ms左右;若Y固定,XZ为变量获取俯视图的图处理时,整张图片的获取也差不多在3ms左右;但右Z固定,获取左视图时,则获取整张图片的时间至少为主视图或俯视图的2倍,最大可能为10倍甚至更多。

原因探索——为何Z固定时,获取整张图片的时间会增大?

多维数组的遍历

首先了解一下多维数组的遍历,遍历元素的方式为:首先递增最右边维度的索引,然后是它左边的一个维度,以此类推,向最左的索引遍历元素。

那么对于一个3*3*3的三维数组,X固定获取的获取,就完全是在一个连续的区域获取,如下所示,对于3*3*3的三维数组,X固定3个区域均为连续在一块儿。

Y固定也是类似,只是相对有些分散,但仍是几个连续的区域,如下所示,Y为0时的黄色区域,Y为1时的白色区域,Y为2时的棕色区域。

Z固定时,看上去也是连续的区域,读取时间应该不会相差太多,如下图所示:

数组在存储单元中存储

存储单元是一维的结构,那么多维数组就需要约定数组的存储次序,C#中数组是以行序为主序(不同语言实现不同)的存储结构,也就是如前面图中3维数组的显示一样以行优先进行存储数据,一行一行将数据存储存储到存储单元。

那么数组的读取,读取X为定值的所有值,就只要知道X固定的第一个值位置,然后顺序读取X为定值的整个区间就可以了;Y固定时与此类似,只是区间会变多;而Z固定就完全不一样了,以前述3*3*3的3维数组为例,Z为1时所有数据,都不是连续的,也就是说它相应的存储位置都需要重新去计算,那么它的读取时间肯定就是最长的了。

如何优化?

那么,才能提高3维数组的读取时间呢?了解了产生性能问题的原因,针对此可以用以下方法进行一定的性能提升。

1. 循环展开

关于循环展开的详细解释,可自行查找相应资料,本文不作赘述。

循环展开代码如下:

展开前:

  for (int i = 0; i < 4; ++i)

  {
      var pixelDataindex = y * rowStride + x * 4 + i;
      if (i != 3)
          PixelData[pixelDataindex] = (byte)HUtoGraysale(ctData16ct[x, y, (int)frameIndex], slope, intercept, imgHeight, imgWidth);
      else
          PixelData[pixelDataindex] = 255;
  }

展开后:

var pixelDataindex = y * rowStride + x * 4;
var gray = (byte)HU2Graysale(ctData16ct[x, y, index], slope, intercept, high, low, imgWidth);
UpdatePixelData(PixelData, pixelDataindex, gray);

展开后涉及的 UpdatePixelData如下:

private static void UpdatePixelData(byte[] PixelData, int pixelDataindex, byte gray)
{
    PixelData[pixelDataindex] = gray;
    PixelData[pixelDataindex + 1] = gray;
    PixelData[pixelDataindex + 2] = gray;
    PixelData[pixelDataindex + 3] = 255;
}

通过前后对比测试结果来看,循环展开后的速度比展开前提高了50%。

2. 多线程

在1中对最内层循环进行了循环展开,在最内层循环的外层循环可以将循环的区域拆分为多个,然后每个区域用一个线程来进行相应的计算,最后将整个计算结果返回即可。

此处注意,并不是拆越多用越多的线程越好,一般不要超过CPU的核心数。

3. 减少不必要的操作

如减少循环中的强制转换,装箱拆箱,以及一些可以转到外边的计算。

4. 优化数据结构

如果性能非常敏感,可以考虑针对你需要的那一维数据进行特殊存储。如本文开头提到的data[x,y,z],可以将Z存储到x的位置,x存储到Z的位置,那么data[z,y,x]的读取速度就会有大的提升。

以上都是在硬件固定的情况下说的,当然,有更好的硬件环境肯定是能提高执行速度的。

参考链接

数组 - C# reference | Microsoft Learn

改几行代码,for循环耗时从3.2秒降到0.3秒!真正看懂的都是牛人!

参考书籍:

数据结构(C语言版)(第2版)——严蔚敏 李冬梅 吴伟民

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

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

相关文章

监管端..

文章目录 1. 登录流程2. 日志AOP 1. 登录流程 使用账号&#xff08;手机号&#xff09;、密码、验证码。登录就是获取token的&#xff0c;输入的账号密码用RSA加密&#xff08;非对称&#xff09; 首先输入账号密码&#xff0c;在发送手机验证码时候先校验账号密码有没有输入…

Python筑基之旅专栏(导航)

目录 一、Python筑基之旅专栏博文清单及链接 二、推荐阅读 一、Python筑基之旅专栏博文清单及链接 01、溯源及发展 02、变量和数据类型 03、搭建Python开发环境及库 04、两个重要函数/列表/元组 05、字符串(一) 06、字符串(二) 07、字符串(三) 08、字典 09、集合 10…

MySQL--存储引擎

一、存储引擎介绍 1.介绍 存储引擎相当于Linux的文件系统&#xff0c;以插件的模式存在&#xff0c;是作用在表的一种属性 2.MySQL中的存储引擎类型 InnoDB、MyISAM、CSV、Memory 3.InnoDB核心特性的介绍 聚簇索引、事务、MVCC多版本并发控制、行级锁、外键、AHI、主从复制特…

springboot+vue2+elementui实现时间段查询

1.前端代码 使用elementui的时间段选择器&#xff1a; <el-date-picker v-model"queryPage.itemTime" type"daterange"value-format"yyyy-MM-dd" class"filter-item" range-separator"至" start-placeholder"创建…

(2024,基于熵的激活函数动态优化,具有边界条件的最差激活函数,修正正则化 ReLU)寻找更优激活函数

A Method on Searching Better Activation Functions 公众号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 动机 4. 方法论 4.1 问题设定 4.1.1 贝叶斯错误率和信息熵 4.1.2 激活…

关于linux磁盘告警问题

案例&#xff1a;我们在执行df命令时&#xff0c;查看到磁盘利用率很高&#xff0c;但是到相对应的目录执行du -sh *来找大文件时进行删除时&#xff0c;发现各个目录相加并不大&#xff0c;如下图&#xff1a; 使用df命令查看到根(/)目录使用到33G&#xff0c;而du命令显示只使…

IBM db2数据库初体验(有图有真相保姆级教程)

前提摘要: 直接安装的是windows 系统版本, 没有安装可视化操作数据库的工具, 直接使用windows中类似cmd窗口输入命令进行操作 1. 安装好windows版本后, 鼠标单击windows最左下角的windows图标, 找到IBM DB2文件夹--> 选择单击展开下拉款--> 单击选中DB2命令窗口, 会出现…

在没有dubbo-admin情况下如何判断zk中注册的dubbo服务是否注册成功

通常我们都是通过dubbo-admin来查看dubbo服务是否注册成功&#xff0c;那么如果没有部署dubbo-admind的情况下&#xff0c;我们如何来判断dubbo服务是否注册成功&#xff1a; 一、首先我们进入到zookeeper bin目录下使用以下指令连接到zk: ./zkCli.sh -server ip:port ip&…

强大的医院绩效考核管理系统源码,支持行业内所有绩效方案,且每步核算都可自主进行方案的新建、调整。

医院绩效考核管理系统是采用B/S架构模式设计、使用JAVA语言开发、后台使用MySql数据库进行管理的一整套计算机应用软件源码。 系统和his系统进行对接&#xff0c;按照设定周期&#xff0c;从his系统获取医院科室和医生、护士、其他人员工作量&#xff0c;对没有录入信息化系统…

从Python代码到pip包:打包Python项目

大家好&#xff0c;在软件开发的世界中&#xff0c;共享和重用代码是至关重要的。Python社区为我们提供了丰富的资源&#xff0c;使得我们能够轻松地与他人分享我们的工作&#xff0c;并从他人的工作中受益。将代码打包成pip包&#xff08;Python包管理器&#xff09;是一种常见…

函数调用时长的关键点:揭秘参数位置的秘密

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、默认参数的秘密 示例代码 二、关键字参数与位置参数的舞蹈 示例代码 总结 一、默认参…

如何编辑 PDF 中的文本

使用 PDF 格式时最常见的挑战之一是弄清楚如何编辑 PDF 文档中的现有文本。该问题不仅影响新手&#xff0c;还影响多年来处理各种文档的专业人士。 PDF 格式专为处理数字纸张而设计。它以原始形式保留所有数据&#xff0c;例如表格、图章和签名。对于需要安全可靠地分发文档的…

香橙派 Kunpeng Pro 上手初体验

香橙派 Kunpeng Pro 上手初体验 目录 香橙派 Kunpeng Pro 上手初体验1.前言2.开箱3.开发板资源介绍硬件规格参数外观规格参数4.系统环境搭建系统镜像烧录ssh连接5.简单测试6.总结 1.前言 我很荣幸能收到了来自CSDN的测评邀请&#xff0c;让我有机会对香橙派最新推出的Kunpeng …

深度学习实战-yolox训练ExDark数据集所遇到的错误合集

跳转深度学习实战-yolox训练ExDark数据集(附全过程代码,超详细教程,无坑!) 一、 训练时出现ap为零 情况1.数据集没导进去 修改exps/example/yolox_voc/yolox_voc_s.py 当然由于image_sets只有一个元素因此修改yolox/data/datasets/voc.py 情况2.iou设置过高 修改yolo…

InteractiveGraph图谱中vue项目中如何使用

InteractiveGraph图谱中vue项目中如何使用 一、下载js和css和字体二、vue2.0项目中引用三、grap组件 一、下载js和css和字体 //在这里面找 https://github.com/grapheco/InteractiveGraph/blob/master/dist/examples/example1.html二、vue2.0项目中引用 //main.js中全局引入$ …

Pytorch深度学习实践笔记8(b站刘二大人)

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;pytorch深度学习 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibi…

新窃密软件 NodeStealer 可以窃取所有浏览器 Cookie

Netskope 的研究人员正在跟踪一个使用恶意 Python 脚本窃取 Facebook 用户凭据与浏览器数据的攻击行动。攻击针对 Facebook 企业账户&#xff0c;包含虚假 Facebook 消息并带有恶意文件。攻击的受害者主要集中在南欧与北美&#xff0c;以制造业和技术服务行业为主。 2023 年 1 …

二维前缀和[模版]

题目链接 题目: 分析: 求二维数组的区间和问题, 可以使用二维前缀和算法注意: 下标从1开始计数第一步: 预处理出来一个前缀和矩阵dp[i][j] 表示: 从[1,1] 位置到[i,j] 位置, 这段区间里面所有元素的和 dp[i][j] 就等于ABCD, A好求, 就是dp[i-1][j-1], 但BC不好求, 所以我们AB…

D - Permutation Subsequence(AtCoder Beginner Contest 352)

题目链接: D - Permutation Subsequence (atcoder.jp) 题目大意&#xff1a; 分析&#xff1a; 相对于是记录一下每个数的位置 然后再长度为k的区间进行移动 然后看最大的pos和最小的pos的最小值是多少 有点类似于滑动窗口 用到了java里面的 TreeSet和Map TreeSet存的是数…

删除edge浏览器文本框储存记录值以及关闭自动填充

当我们点击输入框时总会出现许多以前输入过的信息。 一、删除edge浏览器文本框储存记录值 1、首先按下↓键选中你想删除的信息 二、关闭自动填充。 1、在地址栏输入edge://wallet/settings跳转到以下界面 2、往下滑找到 全部取消即可