试图找到一种构建 Julia `generator` 的方法
Trying to find a way to construct Julia `generator`
我是 Julia 的新手。
我主要在python.
编程
在python中,
如果你想遍历一大组值,
通常构造一个所谓的生成器来节省内存使用量。
这是一个示例代码:
def generator(N):
for i in range(N):
yield i
我想知道 Julia 是否有相似之处。
阅读朱莉娅手册后,
@task 宏似乎与 python 中的生成器具有相同(或相似)的功能。
然而,
经过一些实验,
内存使用量似乎比 julia 中的普通数组大。
我在 IJulia 中使用 @time
来查看内存使用情况。
这是我的示例代码:
[更新]:添加 generator
方法的代码
(generator
方法)
function generator(N::Int)
for i in 1:N
produce(i)
end
end
(生成器版本)
function fun_gener()
sum = 0
g = @task generator(100000)
for i in g
sum += i
end
sum
end
@time fun_gener()
经过时间:0.420731828 秒(分配了 6507600 字节)
(数组版本)
function fun_arry()
sum = 0
c = [1:100000]
for i in c
sum += i
end
sum
end
@time fun_arry()
经过时间:0.000629629 秒(分配 800144 字节)
谁能告诉我为什么 @task
在这种情况下需要更多 space?
如果我想在处理大量值时节省内存使用量,
我能做什么?
我推荐 Carl Vogel 的 "tricked out iterators" 博文,其中详细讨论了 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
更快,分配的内存更少(就像 python 2 中的 xrange
)。
来自博文的片段:
From https://github.com/JuliaLang/julia/blob/master/base/range.jl, here’s how a Range’s iterator protocol is defined:
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)
Notice that the next method calculates the value of the iterator in state i. This is different from an Array iterator, which just reads the element a[i] from memory.
Iterators that exploit delayed evaluation like this can have important performance benefits. If we want to iterate over the integers 1 to 10,000, iterating over an Array means we have to allocate about 80MB to hold it. A Range only requires 16 bytes; the same size as the range 1 to 100,000 or 1 to 100,000,000.
您可以编写生成器方法(使用任务):
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
注意:如果用这个替换 Range,性能会差很多(并且分配更多内存):
julia> @time fun_arry()
elapsed time: 0.699122659 seconds (9 MB allocated)
5000050000
很久以前就有人问过(并回答过)这个问题。由于此问题在 google 搜索中排名靠前,我想提一下问题和答案都已过时。
如今,我建议查看 https://github.com/BenLauwens/ResumableFunctions.jl 的 Julia 库,其中包含实现 Python 类收益生成器的宏。
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
由于它的范围比完整的协程更有限,它也比将值推入通道更有效一个数量级,因为它可以将生成器编译成 FSM。 (频道已经替换了问题和之前答案中提到的旧 produce() 函数)。
话虽如此,如果性能不是问题,我仍然建议将进入通道作为您的第一种方法,因为可恢复函数在编译您的函数时有时会很挑剔,并且偶尔会遇到一些最坏情况的行为。特别是,因为它是一个编译为 FSM 而不是函数的宏,您目前需要注释 Resumable 函数中所有变量的类型以获得良好的性能,这与 vanilla Julia 函数不同,后者在函数运行时由 JIT 处理。第一次打电话。
我认为 Task
已被 Channel()
取代。 Ben Lauwens 的 Fibonacci 生成器的用法是:
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
可以使用
for a in fibonacci(10)
println(a)
end
1
1
2
3
5
8
13
21
34
55
我是 Julia 的新手。 我主要在python.
编程在python中, 如果你想遍历一大组值, 通常构造一个所谓的生成器来节省内存使用量。 这是一个示例代码:
def generator(N):
for i in range(N):
yield i
我想知道 Julia 是否有相似之处。 阅读朱莉娅手册后, @task 宏似乎与 python 中的生成器具有相同(或相似)的功能。 然而, 经过一些实验, 内存使用量似乎比 julia 中的普通数组大。
我在 IJulia 中使用 @time
来查看内存使用情况。
这是我的示例代码:
[更新]:添加 generator
方法的代码
(generator
方法)
function generator(N::Int)
for i in 1:N
produce(i)
end
end
(生成器版本)
function fun_gener()
sum = 0
g = @task generator(100000)
for i in g
sum += i
end
sum
end
@time fun_gener()
经过时间:0.420731828 秒(分配了 6507600 字节)
(数组版本)
function fun_arry()
sum = 0
c = [1:100000]
for i in c
sum += i
end
sum
end
@time fun_arry()
经过时间:0.000629629 秒(分配 800144 字节)
谁能告诉我为什么 @task
在这种情况下需要更多 space?
如果我想在处理大量值时节省内存使用量,
我能做什么?
我推荐 Carl Vogel 的 "tricked out iterators" 博文,其中详细讨论了 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
更快,分配的内存更少(就像 python 2 中的 xrange
)。
来自博文的片段:
From https://github.com/JuliaLang/julia/blob/master/base/range.jl, here’s how a Range’s iterator protocol is defined:
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)
Notice that the next method calculates the value of the iterator in state i. This is different from an Array iterator, which just reads the element a[i] from memory.
Iterators that exploit delayed evaluation like this can have important performance benefits. If we want to iterate over the integers 1 to 10,000, iterating over an Array means we have to allocate about 80MB to hold it. A Range only requires 16 bytes; the same size as the range 1 to 100,000 or 1 to 100,000,000.
您可以编写生成器方法(使用任务):
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
注意:如果用这个替换 Range,性能会差很多(并且分配更多内存):
julia> @time fun_arry()
elapsed time: 0.699122659 seconds (9 MB allocated)
5000050000
很久以前就有人问过(并回答过)这个问题。由于此问题在 google 搜索中排名靠前,我想提一下问题和答案都已过时。
如今,我建议查看 https://github.com/BenLauwens/ResumableFunctions.jl 的 Julia 库,其中包含实现 Python 类收益生成器的宏。
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
由于它的范围比完整的协程更有限,它也比将值推入通道更有效一个数量级,因为它可以将生成器编译成 FSM。 (频道已经替换了问题和之前答案中提到的旧 produce() 函数)。
话虽如此,如果性能不是问题,我仍然建议将进入通道作为您的第一种方法,因为可恢复函数在编译您的函数时有时会很挑剔,并且偶尔会遇到一些最坏情况的行为。特别是,因为它是一个编译为 FSM 而不是函数的宏,您目前需要注释 Resumable 函数中所有变量的类型以获得良好的性能,这与 vanilla Julia 函数不同,后者在函数运行时由 JIT 处理。第一次打电话。
我认为 Task
已被 Channel()
取代。 Ben Lauwens 的 Fibonacci 生成器的用法是:
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
可以使用
for a in fibonacci(10)
println(a)
end
1
1
2
3
5
8
13
21
34
55