Julia并行计算

Julia并行计算

1. 多协程

协程是一种非抢占式多任务处理的方式,相当于轻量级的线程。简单来看,就相当于函数可以在某个点暂停执行并可以f返回结果,之后可以从该点恢复执行。

Julia中的协程通过Channel数据结构实现多任务间的通信。Channel的构造方法为Channel{T=Any}(size::Int=0),T代表Channel中存储数据的类型,size代表缓冲区大小。

Channel中两个重要的操作:

  • put!:向Channel中加入数据,如果Channel已满,这一操作就会阻塞;
  • take!:从Channel中取出数据。

不同的task可以并发地对同一个Channel进行put!take!操作。

可以通过isready来判断Channel中是否有准备好的数据,通过close来关闭Channel,关闭后就不能再写入数据,但还可以读出数据。

mission:创建100个 20 × 20 20 \times 20 20×20的随机矩阵,与固定的 20 × 1 20 \times 1 20×1矩阵相乘,将所有的结果相加。

n = 100

matrixs = Channel{Array{Float64,2}}(n)
result = Channel{Array{Float64,2}}(n)
y = rand(20, 1)

function create_matrix(n)
    for i in 1:n
        put!(matrixs, rand(20, 20))
    end
end

function do_works(n)
    for task_id in 1:n
        x = take!(matrixs)
        put!(result, x * y)
    end
end

@async create_matrix(n)

for i in 1:10
    @async do_works(n)
end

val = 0
for i in 1:n
    global val += sum(take!(result))
end

println("Final result is $val")

2. 多线程

多线程相关的操作在Threads模块中,而Threads隶属于Base模块,因此可以直接使用Threads.

Julia程序线程数的查看与设置:

  • Threads.nthreads()查看Julia的线程数。
  • export JULIA_NUM_THREADS=?(Linux OSX)或Set JULIA_NUM_THREADS=?(Windows)来设置线程数(在terminal中进行设置),JULIA_NUM_THREADS环境变量用来设置 Julia 可用线程的最大数。如果 $JULIA_NUM_THREADS 超过可用的物理 CPU 核心数,那么线程数设置为核心数。要在进入julia前的ternimal中进行设置,只在当前ternimal生效,如果想进行持久化配置可以新建环境变量。

可以通过Threads.threadid()查看线程的id.

**通过Threads.@threads**可以使得一个for循环并行化,这个宏可以将一个迭代空间分割并且并行执行,如:

Threads.@threads for i in 1:10
       println(Threads.threadid())
       end

原子操作

Threads.Atomic{T}可以保证所创建的对象是原子化的,即线程安全的。注意只有简单类型可以原子化,包括BoolIntFloat等。原子化的元素获取要通过[]符号,例:

x = Threads.Atomic{Int}(3)
x	# Base.Threads.Atomic{Int64}(3)
x[]	# 3

原子操作都包含atomic_前缀,常用的原子操作有:

  • atomic_cas!(x::Atomic{T}, cmp::T, newval::T) **where** T,将x与cmp进行比较,如果相等就将newval赋值给x,否则就保持不变;
  • atomic_xchg!(x::Atomic{T}, newval::T) **where** T:将x改变为newval;
  • atomic_add!(x::Atomic{T}, val::T) **where** T <: ArithmeticTypes:原子化地将val与x相加;
  • atomic_sub!(x::Atomic{T}, val::T) **where** T <: ArithmeticTypes:原子化地将val与x相减。

例:

count = Ref(0)
@Threads.threads for i in 1:1000
       count[] += 1;
       end
println(count[])	# 值不为1000
count = Threads.Atomic{Int64}(0)
@Threads.threads for i in 1:1000
       Threads.atomic_add!(count, 1);
       end
println(count[])	# 值为1000

mission:创建100个 20 × 20 20 \times 20 20×20的随机矩阵,与固定的 20 × 1 20 \times 1 20×1矩阵相乘,将所有的结果相加。

n = 100
res = Threads.Atomic{Float64}(0.0)
y = rand(20, 1)

@Threads.threads for i in 1:n
x = rand(20, 20)
Threads.atomic_add!(res, sum(x * y))
end

println("Final result is $res[]")
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值