Parallel processing julia中的归约并行循环

Parallel processing julia中的归约并行循环,parallel-processing,julia,Parallel Processing,Julia,我们可以使用 c = @parallel (vcat) for i=1:10 (i,i+1) end 但是当我试着用推的时候!我得到的不是vcat,而是一些错误。如何使用推送!在这个平行循环中 c = @parallel (push!) for i=1:10 (c, (i,i+1)) end @parallel有点类似于foldlop,itr,因为它使用itr的第一个值作为op.push的第一个初始参数!操作数之间缺少所需的对称性。也许您正在寻找的

我们可以使用

c = @parallel (vcat) for i=1:10
          (i,i+1)
       end
但是当我试着用推的时候!我得到的不是vcat,而是一些错误。如何使用推送!在这个平行循环中

c = @parallel (push!) for i=1:10
     (c, (i,i+1))
end
@parallel有点类似于foldlop,itr,因为它使用itr的第一个值作为op.push的第一个初始参数!操作数之间缺少所需的对称性。也许您正在寻找的是:

julia> c = @parallel (append!) for i=1:10
            [(i,i+1)]
       end
@parallel有点类似于foldlop,itr,因为它使用itr的第一个值作为op.push的第一个初始参数!操作数之间缺少所需的对称性。也许您正在寻找的是:

julia> c = @parallel (append!) for i=1:10
            [(i,i+1)]
       end

详细阐述了丹的观点;要查看并行宏的工作方式,请查看以下两种调用之间的差异:

julia>@我在1:10中的平行打印 i、 i+1 终止 没有,没有,没有,没有,没有,没有,没有,没有,没有,没有 朱莉娅>@1:10中的平行字符串 i、 i+1 终止 1, 22, 33, 44, 55, 66, 77, 88, 99, 1010, 11 从最上面的一个应该很清楚发生了什么。每次迭代产生一个输出。当涉及到在这些输出上使用指定的函数时,这是在输出对中完成的。两个第一对输出馈送至打印,然后打印操作的结果成为下一对中要处理的第一项。由于输出为nothing,因此print不打印任何内容,然后打印3,4。这个print语句的结果是nothing,因此下一个要打印的对是nothing和4,5,依此类推,直到所有元素都被消耗。也就是说,就伪代码而言,发生的情况如下:

步骤1:状态=打印1,2,2,3;国家一文不值 步骤2:状态=打印状态,3,4;国家又一事无成了 步骤3:状态=打印状态,4,5;诸如此类

字符串按预期工作的原因是发生了以下步骤:

步骤1:状态=string1,2,2,3; 步骤2:state=stringstate,3,4; 步骤3:state=stringstate,4,5; 等

通常,传递给并行宏的函数应该是接受两个相同类型的输入并输出相同类型的对象的函数

因此,您不能使用push!,因为它总是使用两个不同类型的输入—一个数组和一个普通元素,并输出一个数组。因此您需要使用append!相反,它符合规范

还要注意的是,输出顺序没有保证。在这里它恰好是有序的,因为我只使用了一个工人。如果你想要一些操作顺序很重要的东西,那么你不应该使用这个结构。例如,很明显,在加法之类的东西中,它并不重要,因为加法是一种完全关联的操作;但如果我使用字符串,如果输出以不同的顺序处理,那么很明显,您可能会得到与预期不同的字符串

编辑-在vcat/append!/索引赋值

我认为最有效的方法实际上是通过对预分配数组进行常规索引。但是在这两者之间!而vcat,append肯定会更快,因为据我所知,vcat总是复制一个副本

基准:

功能与vcat并行!数组{Tuple{Int64,Int64},1} A=i=1:10000时的并行vcat i、 i+1 终止 终止 函数与函数并行!数组{Tuple{Int64,Int64},1} A=@并行追加!因为我在1:10000 [i,i+1]; 终止 终止 函数与预分配并行!数组{Tuple{Int64,Int64},1} @平行于1:10000的i A[i]=i,i+1; 终止 终止 A=数组{Tuple{Int64,Int64},1}10000; 省略了第一次运行,这里的所有基准都来自第二次运行 首先,针对单个工人: @n的时间为1:100;与vcat并行!A.终止 >8.050429秒24.65米分配:75.341 GiB,15.42%gc时间 @n的时间为1:100;与函数并行!A.终止 >0.072325秒1.01米分配:141.846 MiB,52.69%gc时间 @n的时间为1:100;与预分配并行!A.终止 >0.000387秒4.21 k分配:234.750千磅 现在有了真正的并行性: addprocs10; @n的时间为1:100;与vcat并行!A.终止 >1.177645秒160.02 k分配:109.618 MiB,0.75%gc时间 @n的时间为1:100;与函数并行!A.终止 >0.060813秒111.87 k分配:70.585 MiB,3.91%gc时间 @n的时间为1:100;与预分配并行!A.终止 >0.058134秒116.16 k分配:4.174 MiB 如果有人能提出一个更有效的方法,请这样做

请特别注意,索引赋值比其他赋值快得多,因此在本例中,至少在并行化过程中,它的大部分计算似乎丢失了

免责声明:我不认为以上是@parallel法术的正确召唤。我还没有深入研究宏的内部工作原理,以便能够提出其他要求。特别是,我不知道宏导致处理哪些部分
d远程与本地,例如分配部分。建议谨慎,ymmv等。

详细阐述Dan的观点;要查看并行宏的工作方式,请查看以下两种调用之间的差异:

julia>@我在1:10中的平行打印 i、 i+1 终止 没有,没有,没有,没有,没有,没有,没有,没有,没有,没有 朱莉娅>@1:10中的平行字符串 i、 i+1 终止 1, 22, 33, 44, 55, 66, 77, 88, 99, 1010, 11 从最上面的一个应该很清楚发生了什么。每次迭代产生一个输出。当涉及到在这些输出上使用指定的函数时,这是在输出对中完成的。两个第一对输出馈送至打印,然后打印操作的结果成为下一对中要处理的第一项。由于输出为nothing,因此print不打印任何内容,然后打印3,4。这个print语句的结果是nothing,因此下一个要打印的对是nothing和4,5,依此类推,直到所有元素都被消耗。也就是说,就伪代码而言,发生的情况如下:

步骤1:状态=打印1,2,2,3;国家一文不值 步骤2:状态=打印状态,3,4;国家又一事无成了 步骤3:状态=打印状态,4,5;诸如此类

字符串按预期工作的原因是发生了以下步骤:

步骤1:状态=string1,2,2,3; 步骤2:state=stringstate,3,4; 步骤3:state=stringstate,4,5; 等

通常,传递给并行宏的函数应该是接受两个相同类型的输入并输出相同类型的对象的函数

因此,您不能使用push!,因为它总是使用两个不同类型的输入—一个数组和一个普通元素,并输出一个数组。因此您需要使用append!相反,它符合规范

还要注意的是,输出顺序没有保证。在这里它恰好是有序的,因为我只使用了一个工人。如果你想要一些操作顺序很重要的东西,那么你不应该使用这个结构。例如,很明显,在加法之类的东西中,它并不重要,因为加法是一种完全关联的操作;但如果我使用字符串,如果输出以不同的顺序处理,那么很明显,您可能会得到与预期不同的字符串

编辑-在vcat/append!/索引赋值

我认为最有效的方法实际上是通过对预分配数组进行常规索引。但是在这两者之间!而vcat,append肯定会更快,因为据我所知,vcat总是复制一个副本

基准:

功能与vcat并行!数组{Tuple{Int64,Int64},1} A=i=1:10000时的并行vcat i、 i+1 终止 终止 函数与函数并行!数组{Tuple{Int64,Int64},1} A=@并行追加!因为我在1:10000 [i,i+1]; 终止 终止 函数与预分配并行!数组{Tuple{Int64,Int64},1} @平行于1:10000的i A[i]=i,i+1; 终止 终止 A=数组{Tuple{Int64,Int64},1}10000; 省略了第一次运行,这里的所有基准都来自第二次运行 首先,针对单个工人: @n的时间为1:100;与vcat并行!A.终止 >8.050429秒24.65米分配:75.341 GiB,15.42%gc时间 @n的时间为1:100;与函数并行!A.终止 >0.072325秒1.01米分配:141.846 MiB,52.69%gc时间 @n的时间为1:100;与预分配并行!A.终止 >0.000387秒4.21 k分配:234.750千磅 现在有了真正的并行性: addprocs10; @n的时间为1:100;与vcat并行!A.终止 >1.177645秒160.02 k分配:109.618 MiB,0.75%gc时间 @n的时间为1:100;与函数并行!A.终止 >0.060813秒111.87 k分配:70.585 MiB,3.91%gc时间 @n的时间为1:100;与预分配并行!A.终止 >0.058134秒116.16 k分配:4.174 MiB 如果有人能提出一个更有效的方法,请这样做

请特别注意,索引赋值比其他赋值快得多,因此在本例中,至少在并行化过程中,它的大部分计算似乎丢失了


免责声明:我不认为以上是@parallel法术的正确召唤。我还没有深入研究宏的内部工作原理,以便能够提出其他要求。特别是,我不知道宏导致远程处理与本地处理的部分,例如分配部分。请注意,ymmv等。

是追加的运行时间和内存分配!像推还是vcat?@ReD这是一个很好的观点。我添加了基准测试来回答这个问题。所以添加!在顺序和并行方式上都比vcat更有效,而且也比推入式顺序方式更有效。有没有像hcat这样的工作方式?因为它们像vcat一样工作,我正在寻找类似hcat但效率更高的东西
en按索引分配给它。我没用推!在上面的任何地方,都不确定您指的是什么。是否为append分配了运行时间和内存!像推还是vcat?@ReD这是一个很好的观点。我添加了基准测试来回答这个问题。所以添加!在顺序和并行方式上都比vcat更有效,而且也比推入式顺序方式更有效。有没有像hcat这样的工作方式?因为它们像vcat一样工作,我正在寻找类似hcat但效率更高的东西。就像我上面所说的,预先分配一个数组,然后按索引分配给它。我没用推!在上面的任何地方,我都不知道你指的是什么。