问题描述
我有一个包含一个for循环的功能。我想向该函数添加一个参数,让我选择使用
Threads.@threads for i in ...
。
我从而只需要在循环的前注入Threads.@threads
。宏鸵鸟政策工作,因为他们不容处理关键字。
Alterntively我能有这样的事情
if parrallel
inject("Threads.@threads for i in 1:n")
else
inject("for i in 1:n")
end
loop content....
end
我不能找到任何方式插入代码那样。怎么办?
当然可以选择将整个循环放在一个函数中,然后只使用包含 for 循环的 if else 函数,但我更喜欢其余的代码原样。
解决方法
当然可以选择将整个循环放在一个函数中,然后只使用包含 for 循环的 if else 函数,但我更喜欢其余的代码原样。
请注意,高阶函数和 do
blocks 等语法糖使此类解决方案的开发相对简单且易于阅读:
您可以开始定义两个高阶函数来抽象出 for 循环。
# This one is basically `Base.foreach`
function sequential_for(f,iterable)
for i in iterable
f(i)
end
end
# A thread-parallel version
function parallel_for(f,iterable)
Threads.@threads for i in iterable
f(i)
end
end
然后你的函数可以动态决定它想要使用哪个版本的 for 循环:
function my_fun(n; parallel=false)
for_loop = parallel ? parallel_for : sequential_for
x = zeros(Int,n)
# The do syntax avoids having to either
# - define the loop body as a named function elsewhere,or
# - put an hard-to-read lambda directly as argument to `for_loop`
for_loop(1:n) do i
x[i] = Threads.threadid()
sleep(0.1) # Let's make sure we see the effect of parallelism :-)
end
return x
end
示例使用:
julia> @time my_fun(10)
1.025307 seconds (299 allocations: 17.109 KiB)
10-element Array{Int64,1}:
1
1
1
1
1
1
1
1
1
1
julia> @time my_fun(10,parallel=true)
0.235430 seconds (18.44 k allocations: 979.714 KiB)
10-element Array{Int64,1}:
1
1
2
2
3
4
5
6
7
8
,
及时插入代码并不能很好地或轻松地工作。编译器不知道该做什么,它根本不会被优化,也不安全。有关类似问题,请参阅:Julia: inject code into function .
我会通过为 for 循环编写一个单独的函数来编写代码(在我看来是更简洁的方法),或者将 for 循环留在你的第一个函数中,然后将它写成双倍。
类似于:
function forloopcontent()
println(Threads.threadid())
end
function f(parallel::Bool)
if parallel
Threads.@threads for i in 1:10
forloopcontent()
end
else for i in 1:10
forloopcontent()
end
end
end
否则,您还可以为并行版本编写另一个函数,为普通版本编写两种不同的方法。即:
function f(;parallel::Bool=false)
parallel ? (return par_f()) : (return f())
end
function f()
for i in 1:10
println(Threads.threadid())
end
end
function par_f()
Threads.@threads for i in 1:10
println(Threads.threadid())
end
end
对于并行版本,此版本可以称为 f(;parallel=true)
,对于非并行版本可以称为 f(;parallel=false)
。