首页 文章

Rust中的多个特化,迭代器模式

提问于
浏览
4

学习Rust(yay!),我正在尝试理解某些迭代器模式所需的惯用语编程,同时评分最高性能 . 注意:不是Rust的Iterator特性,只是我编写的一个接受闭包并将其应用于某些数据的方法我将从磁盘上移除/内存不足 .

我很高兴看到Rust(LLVM?)采用了我为稀疏矩阵条目编写的迭代器,以及用于执行稀疏矩阵向量乘法的闭包,写为

iterator.map_edges({ |x, y| dst[y] += src[x] });

并在生成的代码中内联了闭包的主体 . 它走得很快 . :d

如果我创建其中两个迭代器,或者第二次使用第一个(不是正确性问题),每个实例都会减慢很多(在这种情况下约为2倍),可能是因为优化器因为多个而不再选择专门化调用站点,最后为每个元素执行函数调用 .

我试图了解是否存在保持上述愉快体验的惯用模式(至少我喜欢它)而不牺牲性能 . 我的选择似乎是(没有人满足这个约束):

  • 接受狡猾的表现(2倍慢不是致命的,但也没有奖品) .

  • 要求用户提供面向批处理的闭包,以便在一小部分数据上作用于迭代器 . 这暴露了迭代器的大部分内部结构(数据被很好地压缩,用户需要知道如何解包它们,或者迭代器需要在内存中存储未包装的批处理) .

  • 在实现假设的 EdgeMapClosure 特性的类型中使 map_edges 泛型,并要求用户为他们想要内联的每个闭包实现这样的类型 . 没有经过测试,但我猜这会向LLVM公开不同的方法,每个方法都能很好地内联 . 缺点是用户必须编写自己的闭包(打包相关状态等) .

  • 可怕的黑客,就像制作不同的方法 map_edges0map_edges1 ,.......或者添加一个通用参数,程序员可以使用该参数使方法不同,但否则会被忽略 .

非解决方案包括“只使用 for pair in iterator.iter() { /* */ } ”;这是数据/任务并行平台的准备工作,我希望能够捕获/移动这些闭包到工作线程,而不是捕获主线程的执行 . 也许我应该使用的模式是写上面的内容,把它放在一个lambda / closure中,然后将它运送到周围?

在一个完美的世界中,如果有一个模式会导致源文件中每次出现 map_edges 会导致二进制文件中出现不同的专用方法,而不会强制整个项目在某些可怕的级别进行优化,那就太棒了 . 我'm coming out of an unpleasant relationship with managed languages and JITs where generics would be the only way (I know of) to get this to happen, but Rust and LLVM seem magical enough that I thought there might be a good way. How do Rust'的迭代器处理这个内联它们的闭包体?或者不是他们(他们应该!)?

1 回答

  • 1

    似乎这个问题是通过Rust的新闭包方法解决的

    http://smallcultfollowing.com/babysteps/blog/2014/11/26/purging-proc/

    简而言之,当您使用新的闭包特征进行通用实现时,上面的选项3(使函数通用关于新的闭包类型)现在可以透明地实现 . Rust为您生成幕后类型 .

相关问题