Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在结构性能影响中包装C#原语

在结构性能影响中包装C#原语
EN

Stack Overflow用户
提问于 2020-11-29 14:49:10
回答 1查看 49关注 0票数 0

我正在写一些关于几何处理的代码,delaunay三角剖分,更具体地说,我需要它更快,所以我使用简单的原语数组作为数据结构来表示三角剖分信息,这是它的一个示例

代码语言:javascript
运行
AI代码解释
复制
        private readonly float2[] points;
        private readonly int[] pointsHalfEdgeStartCount;
        private readonly int[] pointsIncomingHalfEdgeIndexes;

假设我想要快速迭代通过索引点p的所有传入半边,我只需使用预计算数组来实现:

代码语言:javascript
运行
AI代码解释
复制
int count = pointsHalfEdgeStartCount[p * 2 + 1];

for (int i = 0; i < count; i++)
{
    var e = pointsIncomingHalfEdgeIndexes[pointsHalfEdgeStartCount[p * 2] + i]
}

// pointsHalfEdgeStartCount[p * 2] is the start index

这是足够快的,但感觉并不安全或非常清楚。所以我有了将我的索引包装到struct中的想法,以使其更清晰,同时保留性能,类似于:

代码语言:javascript
运行
AI代码解释
复制
public readonly struct Point
{
    public readonly int index;
    public readonly DelaunayTriangulation delaunay

    public Point(int index, DelaunayTriangulation delaunay)
    {
        this.index = index; 
        this.delaunay = delaunay;
    }

            
    public int GetIncomingHalfEdgeCount() => delaunay.pointsEdgeStartCount[index * 2 + 1];
    public HalfEdge GetIncomingHalfEdge(int i)
    {
        return new HalfEdge(
            delaunay,
            delaunay.pointsIncomingHalfEdgeIndexes[delaunay.pointsEdgeStartCount[index * 2] + i]
        );
    }

    //... other methods
}

然后我就可以这样做了:

代码语言:javascript
运行
AI代码解释
复制
int count = p.GetIncomingHalfEdgeCount();

for (int i = 0; i < count; i++)
{
    var e = p.GetIncomingHalfEdge(i);
}

然而,这有点扼杀了我的性能,在我做的基准测试中要慢得多(大约10倍),遍历所有的点和所有传入的半边。我猜是因为在每个point结构中存储对delaunay triangulaiton的引用是一种明显的浪费,并且减慢了所有涉及点的操作,因为有两倍的数据量要移动。

我可以让DelaunayTriangulation成为一个静态类,但由于其他原因它并不实用,所以我这样做了:

代码语言:javascript
运行
AI代码解释
复制
public readonly struct Point
{
    public readonly int index;
    
    public Point(int index) => this.index = index;

            
    public int GetIncomingHalfEdgeCount(DelaunayTriangulation delaunay) => delaunay.pointsEdgeStartCount[index * 2 + 1];
    public HalfEdge GetIncomingHalfEdge(DelaunayTriangulation delaunay, int i)
    {
        return new HalfEdge(
            delaunay.pointsIncomingHalfEdgeIndexes[delaunay.pointsEdgeStartCount[index * 2] + i]
        );
    }

    //... other methods
}

我可以这样做:

代码语言:javascript
运行
AI代码解释
复制
int count = p.GetIncomingHalfEdgeCount(delaunay);

for (int i = 0; i < count; i++)
{
    var e = p.GetIncomingHalfEdge(delaunay, i);
}

它的速度要快得多,但仍然比使用简单int的第一种方法慢2.5倍。我想知道这是否可能是因为我在第一个方法中获得了int,而在其他方法中获得了HalfEdge结构(类似于Point结构的结构,只包含一个索引作为数据和几个方法),并且当我使用Point实例化一个新的HalfEdge结构时,普通的int和更快的结构之间的差异消失了。虽然我不确定为什么仍然如此costly.Weirder,但为了清楚起见,我尝试了在Delaunay类中编写方法而不是Point结构的选项:

代码语言:javascript
运行
AI代码解释
复制
// In the DelaunayTriangulation class:

public int GetPointIncomingHalfEdgeCount(Point p) => pointsEdgeStartCount[p.index * 2 + 1];
public HalfEdge GetPointIncomingHalfEdge(Point p, int i)
{
    return new HalfEdge(
        pointsIncomingHalfEdgeIndexes[pointsEdgeStartCount[p.index * 2] + i]
        );
}

我是这样使用它的:

代码语言:javascript
运行
AI代码解释
复制
int count = delaunay.GetPointIncomingHalfEdgeCount(p);

for (int i = 0; i < count; i++)
{
    var e = delaunay.GetPointIncomingHalfEdge(p, i);
}

它比之前的方法慢了3倍!我不知道为什么。

我尝试使用反汇编来查看生成了什么机器代码,但失败了(我正在使用Unity3D)。我是否注定要在数组中依赖普通的int和合理的变量命名,并放弃尝试进行一些编译时类型检查(这个int真的是点索引吗?)

我甚至没有提出其他问题,比如,当我尝试使用具有如下收益的IEnumerable类型时,为什么它会更慢:

代码语言:javascript
运行
AI代码解释
复制
public IEnumerable<int> GetPointIncomingHalfEdges(Point p)
{
    int start = pointsEdgeStartCount[p.index * 2]; // this should be a slight optimization right ?
    int count = pointsEdgeStartCount[p.index * 2 + 1];
    for (int i = 0; i < count; i++)
    {
        yield pointsIncomingHalfEdgeIndexes[start + i];
    }
}
EN

回答 1

Stack Overflow用户

发布于 2020-11-29 17:19:12

我已经为主动内联添加了一个编译器指令,它似乎弥补了时间上的差异!由于某些原因,编译器无法正确内联以下内容:

代码语言:javascript
运行
AI代码解释
复制
var e = delaunay.GetPointIncomingHalfEdge(p, i);

虽然它成功地通过

代码语言:javascript
运行
AI代码解释
复制
var e = p.GetIncomingHalfEdge(delaunay, i);

为什么?我不知道。然而,如果我能够看到代码是如何编译的,而我不知道如何做到这一点,那就容易多了。我会搜索它,也许会打开另一个问题,如果我找到更好的解释,我会回来的!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65061400

复制
相关文章
java – 为什么InputStream#read()返回一个int而不是一个字节?
首先字节正好是8位,所以使用8位的char类型数据来与字节数据相互一一对应是最好的选择?但是为何方法InputStream#read()需要返回int类型值呢?
Fisherman渔夫
2020/02/19
1.2K0
springcloud 返回的数据为XML 而不是JSON
本人的原因是因为引入了jackson-dataformat-xml依赖导致的,下面查看自己项目是否包含此依赖,如果包含的话,可以去掉。 有的人添加了下面注解后可以解决,不过我这里没有解决。还是依靠上图
qubianzhong
2019/04/01
2.3K0
springcloud 返回的数据为XML 而不是JSON
为什么 useState 返回的是 array 而不是 object?
这里可以看到 useState 返回的是一个数组,那么为什么是返回数组而不是返回对象呢?我们在自定义 hook 时应该返回什么类型呢?
小鑫
2022/04/26
2.3K0
js如何返回异步函数结果
假设您有这样一个问题:您正在进行一个异步调用,并且需要从原始函数返回该调用的结果。
IT工作者
2022/01/01
6.4K0
DevOps是一个接口,而不是一个类
职位通常定义一个人需要执行的任务。“软件开发人员”开发软件,“系统管理员”管理系统,“团队负责人”领导团队。他们执行任务的质量可以用来评估他们的绩效。
DevOps云学堂
2021/05/11
1.1K0
DevOps是一个接口,而不是一个类
JS如何返回异步调用的结果?
这个问题作者认为是所有从后端转向前端开发的程序员,都会遇到的第一问题。JS前端编程与后端编程最大的不同,就是它的异步机制,同时这也是它的核心机制。
LIYI
2023/03/06
5.6K0
JS如何返回异步调用的结果?
去解决更多的问题,而不是如何最好地解决一个问题
有些人非常勤奋,别人休息和娱乐的时候,都在工作学习。但是努力了一辈子,人生也没有显著的提升,就像报道里经常说的:"某某在平凡的岗位上,勤勤恳恳工作了一辈子"。
春哥大魔王
2018/09/21
7570
去解决更多的问题,而不是如何最好地解决一个问题
mybatis返回结果处理
当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。如果返回的是一条记录可以用集合接收
一个风轻云淡
2023/10/15
2500
mybatis返回结果处理
C++核心准则编译边学-F.20 输出结果时更应该使用返回值而不是输出参数
A return value is self-documenting, whereas a & could be either in-out or out-only and is liable to be misused.
面向对象思考
2020/03/25
1.4K0
Java 日期类型比较没有返回正确的结果
最近在数据库处理的时候发现日期对比的时候没有返回正确的结果。 但是保存的时间实际上是相同的。 代码如下: if (!mlsPhoto.getDateUpdate().equals(photo.getDateUpdate())) { } 因为这里使用了 equals 方法。 问题解决 经过 Debug 后,这 2 个日期的纳秒数是不同的,查看下对象如下。 我们会发现其中一个对象有纳秒,一个对象没有。 但是 fastTime 是相同的。 如果使用 equals 那么这个方法比较的是毫秒,所以是不相等的。
HoneyMoose
2021/12/21
3.5K0
java 查看进程状态_java执行shell命令并返回结果
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/172503.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/22
8990
java 查看进程状态_java执行shell命令并返回结果
【说站】Python如何用下标取得列表的单个值
1、使用的下标超出了列表中值的个数,Python 将给出 IndexError 出错信息。
很酷的站长
2022/11/24
1.3K0
【说站】Python如何用下标取得列表的单个值
一文读懂《Effective Java》第43条:返回零长度的数组或集合,而不是null
对于一个返回null 而不是零长度数组或者集合的方法,客户端几乎每次用到该方法都可能会忘记写专门处理null 返回值的代码,进而导致NPE。
后台技术汇
2022/05/28
1.6K0
Feign配置微服务间调用返回XML而不是Json的解决方案
springcloud中的微服务之间通过网关的api调用时,返回的是xml格式,而不是相应的json串,如果想要返回json格式如何处理呢
在水一方
2022/06/14
1.6K0
Feign配置微服务间调用返回XML而不是Json的解决方案
2022-12-15:寻找用户推荐人。写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都 不是 2。对于示例数据,结果
2022-12-15:寻找用户推荐人。写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都 不是 2。
福大大架构师每日一题
2023/02/01
8020
更聪明地学习,而不是苦读——《如何高效学习》
所以,需要持续大量学习的童鞋,比方说我等程序员们,除了要从知识的海洋中精挑细选出我们想要的内容,挑完了还得高效学习,不然成长的速度可能远远赶不上脱发的速度,沦落到「他变秃了,也没变强」的尴尬境地。
mzlogin
2020/05/21
6710
mybatis返回结果类型(resulttype返回list)
这样设置返回类型为resultClass=”java.util.HashMap”,查询时执行queryForList
全栈程序员站长
2022/08/01
5.7K0
何时使用MongoDB而不是MySql
MySQL 和 MongoDB 是两个可用于存储和管理数据的数据库管理系统。MySQL 是一个关系数据库系统,以结构化表格格式存储数据。相比之下,MongoDB 以更灵活的格式将数据存储为 JSON 文档。两者都提供性能和可扩展性,但它们为不同的应用场景提供了更好的性能。
wayn
2023/08/09
1.1K0
何时使用MongoDB而不是MySql
SpringBoot统一返回结果
在后台开发时,控制台得到的数据格式会有不同,这时我们需要设置统一返回结果,方便我们分析数据以及对数据进行管理。
算法与编程之美
2022/05/23
9480
SpringBoot统一返回结果
何时使用Kafka而不是RabbitMQ
Kafka 和 RabbitMQ 都是流行的开源消息系统,它们可以在分布式系统中实现数据的可靠传输和处理。Kafka 和 RabbitMQ 有各自的优势和特点,它们适用于不同的场景和需求。本文将比较 Kafka 和 RabbitMQ 的主要区别,并分析何时使用 Kafka 而不是 RabbitMQ。
wayn
2023/06/26
3940
何时使用Kafka而不是RabbitMQ

相似问题

Java XPath返回单个结果而不是NodeSet

11

findById返回文档列表,而不是单个结果

21

Java LDAP总是返回单个值,而不是列表

10

获取列表中的结果,而不是单个列表

129

Swift NSPredicate正在返回所有结果,而不是单个结果。

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档