我是朱莉娅的新手.我主要在python中编程.
在python中,如果要迭代一大组值,通常会构造一个所谓的生成器来节省内存使用量.这是一个示例代码:
def generator(N):
for i in range(N):
yield i
Run Code Online (Sandbox Code Playgroud)
我想知道朱莉娅是否有类似的东西.阅读julia手册后,@ task macro似乎与python中的生成器具有相同(或类似)的功能.然而,经过一些实验,在julia中,内存使用量似乎比通常的数组大.
我@time在IJulia中使用来查看内存使用情况.这是我的示例代码:
[更新]:添加generator方法代码
(generator方法)
function generator(N::Int)
for i in 1:N
produce(i)
end
end
Run Code Online (Sandbox Code Playgroud)
(发电机版)
function fun_gener()
sum = 0
g = @task generator(100000)
for i in g
sum += i
end
sum
end
Run Code Online (Sandbox Code Playgroud)
@time fun_gener()
已用时间:0.420731828秒(已分配6507600字节)
(阵列版)
function fun_arry()
sum = 0
c = [1:100000]
for i in c
sum += i
end
sum
end
Run Code Online (Sandbox Code Playgroud)
@time fun_arry()
已用时间:0.000629629秒(已分配800144个字节)
谁能告诉我为什么@task在这种情况下需要更多空间?如果我想将内存使用量保存为处理大量值,我该怎么办?
And*_*den 13
我推荐Carl Vogel 的"欺骗迭代器"博客文章,它详细讨论了julia的迭代器协议,任务和协同例程.
另请参阅julia文档中的task-aka-coroutines.
在这种情况下,您应该使用Range类型(定义迭代器协议):
julia> function fun_arry()
sum = 0
c = 1:100000 # remove the brackets, makes this a Range
for i in c
sum += i
end
sum
end
fun_arry (generic function with 1 method)
julia> fun_arry() # warm up
5000050000
julia> @time fun_arry()
elapsed time: 8.965e-6 seconds (192 bytes allocated)
5000050000
Run Code Online (Sandbox Code Playgroud)
分配的速度更快,内存更少(就像xrange在python 2中一样).
来自博客帖子的片段:
从https://github.com/JuliaLang/julia/blob/master/base/range.jl,这里是如何定义Range的迭代器协议:
Run Code Online (Sandbox Code Playgroud)start(r::Ranges) = 0 next{T}(r::Range{T}, i) = (oftype(T, r.start + i*step(r)), i+1) next{T}(r::Range1{T}, i) = (oftype(T, r.start + i), i+1) done(r::Ranges, i) = (length(r) <= i)请注意,下一个方法计算状态i中迭代器的值.这与Array迭代器不同,后者只从内存中读取元素a [i].
利用这种延迟评估的迭代器可以带来重要的性能优势.如果我们想迭代整数1到10,000,迭代一个数组意味着我们必须分配大约80MB来保存它.范围只需要16个字节; 大小与1至100,000或1至100,000,000相同.
您可以编写生成器方法(使用Tasks):
julia> function generator(n)
for i in 1:n # Note: we're using a Range here!
produce(i)
end
end
generator (generic function with 2 methods)
julia> for x in Task(() -> generator(3))
println(x)
end
1
2
3
Run Code Online (Sandbox Code Playgroud)
注意:如果用此替换Range,性能会更差(并分配更多内存):
julia> @time fun_arry()
elapsed time: 0.699122659 seconds (9 MB allocated)
5000050000
Run Code Online (Sandbox Code Playgroud)
很久以前,这个问题被提出(并得到了回答).由于这个问题在谷歌搜索中排名很高,我想提一下问题和答案都已过时.
现在,我建议用一个实现类似Python的yield生成器的宏来检查https://github.com/BenLauwens/ResumableFunctions.jl for Julia库.
using ResumableFunctions
@resumable function fibonnaci(n::Int) :: Int
a = 0
b = 1
for i in 1:n-1
@yield a
a, b = b, a+b
end
a
end
for fib in fibonnaci(10)
println(fib)
end
Run Code Online (Sandbox Code Playgroud)
由于它的范围比完整协同程序更受限制,因此它可以比将值推入通道的效率高一个数量级,因为它可以将生成器编译成FSM.(频道已经取代了问题中提到的旧的produce()函数和之前的答案).
话虽如此,如果性能不是问题,我仍然建议将其作为第一种方法进入通道,因为在编译函数时,可恢复函数有时会很糟糕,并且偶尔会遇到一些最坏情况的行为.特别是,因为它是一个编译为FSM而不是函数的宏,所以你当前需要注释Resumable函数中所有变量的类型以获得良好的性能,这与vanilla Julia函数不同,其中当函数是JIT时由JIT处理第一次打电话
我认为Task已被取代Channel()。就本劳文斯的斐波那契发电机而言,用法为:
fibonacci(n) = Channel(ctype=Int) do c
a = 1
b = 1
for i in 1:n
push!(c, a)
a, b = b, a + b
end
end
Run Code Online (Sandbox Code Playgroud)
可以使用
for a in fibonacci(10)
println(a)
end
1
1
2
3
5
8
13
21
34
55
Run Code Online (Sandbox Code Playgroud)