带有元组解包的过程虚拟参数

问题描述 投票:0回答:1

在BenchmarksGame网站的nbody程序中,我注意到

sumOfSquares()
的写法如下(在代码末尾):

// compute the sum of squares of a 3-tuple's elements
inline proc sumOfSquares((x,y,z)) {
  return x**2 + y**2 + z**2;
}

我想知道上面的伪参数表示法

(x,y,z)
是否像“元组解包”一样工作,所以与下面的类似?

var (x,y,z) = {actual tuple on the caller side};

为了理解它,我尝试了以下代码,似乎实际的元组

t
通过值传递给
myproc((x,y,z))
,每个组件都可以在例程中修改。 (通过 ATO 网站测试)

更具体地说,下面的 (1) 行和 (2) 行的含义相似,并且 (2) 和 (3) 行的工作原理基本相同(除了解包)。这种理解正确吗...?

var t_orig = (1.0, "hello");
var t = t_orig;
writeln("t = ", t);

var (x,y) = t;       // (1)
x = 100; y = "hi";
writeln("x = ", x, " y = ", y, " t = ", t);  // t -> (1.0, "hello")

ref (p,q) = t;     // (1')
p = 100; q = "hi";
writeln("p = ", p, " q = ", q, " t = ", t);  // t -> (100.0, "hi")

proc myproc((x, y))   // (2)
{
  x += 1.0;
  y += " world";
  writeln("myproc(): ", (x,y));
}

proc myproc2(in u)        // (3)
// proc myproc2(ref u)    // t -> (2.0, "hello world")
// proc myproc2(inout u)  // t -> (2.0, "hello world")
// proc myproc2(u)        // (4) error: 'u' is const and cannot be modified
{
  u[0] += 1.0;
  u[1] += " world";
  writeln("myproc2(): ", u);
}

t = t_orig;
myproc(t);           // (2.0, "hello world")
writeln("t = ", t);  // (1.0, "hello")

t = t_orig;
myproc2(t);
writeln("t = ", t);   // depends on routines

Results from ATO:
t = (1.0, hello)
x = 100.0 y = hi t = (1.0, hello)
p = 100.0 q = hi t = (100.0, hi)
myproc(): (2.0, hello world)
t = (1.0, hello)
myproc2(): (2.0, hello world)
t = (1.0, hello)

我还想知道为什么

nbody
程序使用像(2)这样的函数形式而不是(3)。这主要是为了代码的可读性,还是可能是性能方面的考虑……?

tuples chapel
1个回答
0
投票

感谢您的提问。

我想知道上面的伪参数 (x,y,z) 表示法是否像“元组解包”一样工作,与以下内容非常相似? […] ……这个理解正确吗……?

是的,我认为您的理解是正确的。 在语言规范中提供了此功能的简要文档,但可以说可以进行改进以澄清行为。

我想强调的一件事是你提到“它似乎[通过值传递]…”因为,为了支持编译器优化,我相信 Chapel 故意避免指定诸如实现如何传递元组或 at将在什么时候制作本地可修改的副本(或者即使它们......例如,如果不需要它们)。

最终,我相信 Chapel 的目的是支持像这样的去元组正式论证的论证意图(如

ref
inout
),这样你就可以写:

proc myproc(ref (x, y)) { … }
// or
proc myproc(inout (x, y)) { … }

并让您的程序通过本地分配对

x
y
修改原始元组。 如果支持,这将导致行为更像您的 (1')/
ref t
inout t
情况。 但如果您尝试过,您可能会发现,现在不支持它:

error: intents on tuple-grouped arguments are not yet supported

我还想知道为什么nbody程序使用像(2)这样的函数形式而不是(3)。这主要是为了代码的可读性,还是可能是性能方面的考虑……?

我相信我们采取这种方法主要是出于风格而非性能的原因。 具体来说,当结果足够简洁和清晰时,我倾向于避免对元组进行索引,以避免陷入基于 1 与基于 0 的索引假设或战争。 就我个人而言,我也更喜欢在这样的上下文中将组件视为“x”、“y”和“z”,而不是“t[0]”、“t1”、“t[2]”。

也就是说,由于 CLBG 支持通过紧凑性比较代码,因此看看是否重写如下会很有趣:

inline proc sumOfSquares(in t) {
  return t[0]**2 + t[1]**2 + t[2]**2;
}

使用网站的指标生成更紧凑的代码(其中涉及删除注释和不必要的空格,然后对结果进行 gzip 压缩)。

就性能而言,该过程被声明为

inline
的事实将导致其主体在调用点处内联,这使我期望后端编译器将优化消除两种方法之间的任何实现差异。 也就是说,我承认最近没有比较过它们(如果有的话)。 如果您发现它们的表现不同,那会很有趣。 如果是这样的话,我不知道有什么理由不能改进编译器以使它们具有相同的性能。 当然,我们的目标是让像这样的细微风格差异表现相同。

© www.soinside.com 2019 - 2024. All rights reserved.