Julia的简介及并行程序情况

一、Julia是什么

Julia 是个灵活的动态语言,适合科学和数值计算,性能可与传统静态类型语言媲美。基本上长这个样子。

Julia的简介及并行程序情况_第1张图片

两种运行方法一种是交互式,如:


另一种是解释式的,如julia hello.jl


二、为什么是julia

Julia的主要特点有:核心语言较小;标准库是用Julia 本身写的,包括整数运算在内的基础运算。拥有完善的类型,方便构造对象和类型声明。基于参数类型进行函数重载。参数类型不同,自动生成高效、专用的代码。性能高,接近静态编译语言。不需封装或API而直接调用C函数。

最重要的是,为并行和分布式计算而设计的Julia,本身对并行有良好的支持。

三、最重要的是并行

1)   为什么要并行

并行计算的基本思想就是把复杂的工作进行分解,分解成可以同时进行的多个子任务,来缩短任务的完成时间,提升系统的吞吐性能。单线程独占模式下的程序需要等待一个任务完成,才会启动另一个任务。如果一个任务在进行大量的I\O操作,其他任务也没有办法开始,只能等待。而这时CPU就会空闲。所以多线程并发就表现出了很好的资源利用能力,一个线程在I\O操作,另一个就可以利用CPU(或其他计算)资源。

2)     如何并行

Julia提供了一个基于消息传递的多进程环境,能够同时在多处理器上使用独立的内存空间运行程序。这个内存空间由每个CPU单独控制,他们之间通过内部消息机制来通信。Julia的消息机制不同于MPI,并不是收发,而是看起来更像函数调用的方式。

并行程序的两个要素远程引用和远程调用:远程引用是引用其他特定处理器的对象,这个引用可被其它任何处理器访问。远程调用是某处理器调用其它(或自身)处理器。远端调用的结果放回远程引用,可以使用fetch来抓取结果。例如:r=remote_call(2,rand,2,2)这个远程调用中,第一个参数为核心序号,第二个参数为调用的函数名,其后为该函数rand的参数。获取该结果为fetch(r)。

而宏@spawnat用来进行调用,更为方便。如 @spawnat2 1+fetch(r)在第二个核心上进行加1操作。如果要立即获取结果,请使用remote_call_fetch(2, ref, r, 1, 1)。

为了保证程序在所有核心上都可以使用,建议使用require("myfile")的方法导入文件。了解当前系统核数的情况,请采用np = nprocs()方法。

3)     其它并行方法的问题和解决思路

使用它并行程序做运算,我们需要:合理地把复杂任务进行拆解,考虑拆解后的并行子任务的个数和机器处理核的个数关系,以及每个子任务处理的时间,对之上的数据进行平衡处理。提升比较明显的是那种处理的数据量很大,或者要执行的数据处理任务繁重,并且这些任务本身就可以分解为互不相关的子任务。

随之而来的问题是:开发复杂性增高,需要考虑子任务的协调,以及彼此间的通信,而且还要基于机器性能考虑开线程个数。

Julia是采用远程调用和动态数组的方式来解决这些问题。现在举例说明。

四、一个例子

1)     例子说明

北京市有3723条公交路线(包括上下行)。现需求根据本月历史数据,计算每条线路的平均运行时间。本实验中,我们展示采用随机生成数据。实验环境是:3GHz*4core CPU,4GB内存,带GPU卡,Linux操作系统。采用的Julia版本为0.1.2。

2)     解决办法

Julia的并行解决办法,是将该问题分解为平均1000条公交线的4个数据集,交给不同的CPU内核来运算。首先我们定义一个最内部求平均运行时间的函数。

functionzm(a::Array,x::Int32,y::Int32,z::Int32)

        b=reshape(a,x,y,z)

        sum=Array(Float32,x,y)

        fori=1:x

                forj=1:y

                        fork=1:z sum[i,j]= sum[i,j] + b[i,j,k] end

                end

        end

        sum/z

end

该函数返回求出的平均数。该平均数结果为二维数组。

现在编写主程序,在主文件里生成三维随机数数组,他们的值为1。该随机数组为4000*40*100,代表4000条线路上的40个站点每天100趟的车次信息。程序主体如下:

#importall Base  #需导入该包

const X=4000; const Y=40; const Z=200;const NP=4; XX=1000  #定义常量

busIni = Array(Int32,X,Y,Z)  #定义数据

fill!(busIni,1)  #填充为1

busInter = Array(Int32,X,Y,Z)  #定义中间计算结果数组

addprocs_local(3)  #增加并行运算的核数,增加三个,就总共为四个核参与运算。

pastart=time()  #计时开始

pbInter1=busInter[1:XX,1:Y,1:Z]  #拆分数组

pbInter2=busInter[XX+1:2XX,1:Y,1:Z]

pbInter3=busInter[2XX+1:3XX,1:Y,1:Z]

pbInter4=busInter[3XX+1:X,1:Y,1:Z]

require("zm.jl")  #导入ZM函数

rzm1=remote_call(1,zm,pbInter1,XX,Y,Z)  #在1号核上调用zm函数,传入的值为拆分的第一个数组。

rzm2=remote_call(2,zm,pbInter2,XX,Y,Z)

rzm3=remote_call(3,zm,pbInter3,XX,Y,Z)

rzm4=remote_call(4,zm,pbInter4,XX,Y,Z)

pbInter=vcat(fetch(rzm1),fetch(rzm2),fetch(rzm3),fetch(rzm4))  #取回数据并组合

println("耗时", time()-pastart, "s")  #显示计算时间

3)     性能表现

在上述实验配置下,不同规模运行情况

1  运行时间对比

 

串行时间

并行时间

加速比

1600000000

11.2

3.1

3.61

4)     下一步优化

下一步可能的研究和优化点

1.进一步提高数据划分和组合的效率,减少IO时间。

2.优化和提高并行算法,使其更搞笑。

3.开发通用并行算法程序库。

五、总结

Julia为开发和运行并行程序、解决大规模数据运算问题提供了方便快捷、功能强大的语言工具。构建基于Julia和高性能计算机的云平台,将高性能计算机的计算能力通过服务的方式提供给异地客户,将是一个很有前景的应用。

参考

1.       Julia主页

2.       Ubuntu下安装Julia

3.       Julia运行程序

4.       第一个Julia程序

你可能感兴趣的:(Julia的简介及并行程序情况)