hic*_*cup 4 multithreading julia
当我在具有8个逻辑CPU内核的64位Windows 8.1 PC上的Julia v0.3.7的REPL中执行此操作时:
blas_set_num_threads(CPU_CORES)
const v=ones(Float64,100000)
@time for k=1:1000000;s=dot(v,v);end
Run Code Online (Sandbox Code Playgroud)
我在任务管理器或Process Explorer的CPU仪表中观察到只使用了12.5%的CPU(1个逻辑CPU核心).在Windows 7和Windows 8.1上,我也对Julia v0.3.5也有同样的看法.我也通过在命令行上启动"Julia -p 8"来观察相同的行为.在没有"-p 8"命令行选项的情况下返回运行Julia REPL,我尝试了这个测试:
blas_set_num_threads(CPU_CORES)
@time peakflops(10000)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,CPU仪表显示100%的CPU使用率.
既然dot()和peakflops()都使用BLAS(在我的情况下是OpenBLAS),我希望两者都使用指定的线程数blas_set_num_threads().但是,只有后一种功能才能实现.dot()可能是在OpenBLAS中是由于一个bug 的行为?
我试图通过使用矩阵乘法函数来解决Julia的缺点.但是,我正在迭代dot()GB大小的2D数组的子向量上的操作,其中子向量使用连续的内存.矩阵乘法迫使我转置每个向量,从而创建一个副本.这在内循环中是昂贵的.因此,我的选择似乎要么学习如何使用Julia的并行处理命令/宏,要么回到Python(英特尔的MKL BLAS按预期运行ddot()).由于dot()在我尝试编写的例程中消耗99%CPU的功能,我希望OpenBLAS能在Julia中为我提供用户友好的最佳解决方案,而不必担心引擎盖下的所有并行处理复杂性.但也许它不是那么糟糕......
我可以使用一些创建多线程dot()函数.一些示例代码将是最好的帮助.当所有线程在同一台机器上运行时,是否需要使用SharedArray?如果是这样,从Array转换为SharedArray会创建副本吗?由于我的数组非常大,我不希望同时在内存中有两个副本.因为我的向量大约是100,000个,并且来自一个数组的向量以不可预测的顺序使用,对我来说最好的多线程解决方案是dot()函数,它将任务分配到可用的核心中,并对结果进行求和.每个核心.如何在Julia中像BLAS一样高效地完成这项工作?
我在这里看到Tim Holy的答案:
BLAS诉Julia SharedArray对象的并行更新
然而,他的例子(我认为)dot()在一个核心上执行整个函数,并且它不回答我的其他问题.
编辑1:我尝试使用"-p 8"命令行选项运行Julia并dot()在上面替换上面的示例innersimd():http:
//docs.julialang.org/en/release-0.3/manual/performance-tips/
仍然只使用1个核心.我修改innersimd()为键入其参数::Array{Float64, 1}然后::SharedArray{Float64, 1},但这仍然使用1核心.:(
编辑2:我测试了Julia的矩阵乘法(BLAS'gemm!()函数):
blas_set_num_threads(CPU_CORES)
const A=ones(Float64,(4,100000))
const B=ones(Float64,(100000,4))
@time for k=1:100000;s=A*B;end
Run Code Online (Sandbox Code Playgroud)
即使Julia没有使用"-p"命令行选项,Julia也只使用了一个核心.
编辑3:这是Python的可比测试代码:
import numpy as np
from scipy.linalg.blas import ddot
from timeit import default_timer as timer
v = np.ones(100000)
start = timer()
for k in range(1000000):
s = ddot(v,v)
exec_time=(timer() - start)
print
print("Execution took", str(round(exec_time, 3)), "seconds")
Run Code Online (Sandbox Code Playgroud)
我在64位Anaconda3 v2.1.0和WinPython上得到了相同的结果:7.5秒.与我的问题中的第一个例子相比,使用带有OpenBLAS的Julia 0.3.7,在28秒内执行.这使得Python比Julia快4倍,这可以通过OpenBLAS的单线程实现来解释ddot().
编辑4:我在Python中进行了一些测试,在我的内循环(N = 100000)中有效地执行了(4xN)*(Nx2)矩阵乘法,我发现它的速度慢了两倍多.我怀疑这是因为缓存需求现在大8倍,因此缓存命中率更差.为了保持Julia中的缓存需求与Python相同,Julia的问题是:如何将我的100000长度向量分成4个块并ddot()并行执行OpenBLAS的单线程(并对结果求和)?长度可能不是4的倍数.由于OpenBLAS是单线程的,我可以在同一会话中使用"-p 8"命令行参数和多线程其他自定义函数运行Julia.
编辑5:使用"-p 8"命令行参数运行Julia v0.3.7,我观察到OpenBLAS gemm!()函数确实以多线程运行(对于某些矩阵维度):
blas_set_num_threads(CPU_CORES)
const a = rand(10000, 10000)
@time a * a
Run Code Online (Sandbox Code Playgroud)
原因是OpenBLAS ddot似乎不是多线程的.我认为他们主要为BLAS-3函数实现多线程xgemm,所以如果可能的话,最好的办法是用矩阵乘法来编写你的问题.
如果您能举例说明如何使用矩阵乘法,这将有所帮助.也许可以避免换位.你是怎么用Python做的?这一切都只是BLAS,所以Julia应该能够在这里做到和Python一样好.
使用-p 8旗帜运行Julia会启动九个Julia副本并关闭BLAS中的多线程,因此它可能会使情况变得更糟.
编辑1:我在单线程和多线程模式下尝试使用OpenBLAS和MKL,如果有任何差异,单线程更快.我不确定OpenBLAS是否会为您的示例使用多个线程.可能是因为多线程加速对于瘦问题很难实现,因此它们只会针对更胖的问题启用多线程.如果在同一台机器上运行Python的示例明显更快?如果是这样,请提供Python示例,以便我可以与我的计算机上的示例进行比较.
编辑2:我可以确认ddotMKL 的加速.确切地说,编辑1中的评论是关于dgemm.积极努力使Julia成为多线程,当发生这种情况时,一个线程化的Julia实现可能比OpenBLAS更快ddot.你现在的选择是其中之一
如果可能的话,重写你的问题,使OpenBLAS' dgemm使用多个线程,即使用更胖的矩阵.在我的机器上,多线程似乎开始了n=16.如果这是可能的,我认为它不会比MKL慢.通常,OpenBLAS' dgemm与MKL相比较.
请求OpenBLAS开发人员制作ddot多线程.如果你能为项目提供一个版本会更好,但是高性能的BLAS代码很难写.
购买MKL并开始销售包括MKL在内的Revolution Julia以支付许可费用.
编辑3:比较全部是在Julia的Ubuntu机器上进行的,具有Nahalem架构和80个核心(但我最多只使用了16个).我使用了Julia相同开发版本的两个不同版本:一个与源自OpenBLAS构建链接,一个与MKL链接.我还在最近的Haswell系统上尝试了使用OpenBLAS的Julia,以确保ddot在该架构上没有实现线程化.