试图找到一种方法来构建朱莉娅`generator'

Dbo*_*iao 17 generator julia

我是朱莉娅的新手.我主要在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的迭代器协议:

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)
Run Code Online (Sandbox Code Playgroud)

请注意,下一个方法计算状态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)

  • 尼斯.很抱歉忘记发布生成器方法的代码.它与你的完全一样.感谢您的回答. (2认同)

sao*_*lof 8

很久以前,这个问题被提出(并得到了回答).由于这个问题在谷歌搜索中排名很高,我想提一下问题和答案都已过时.

现在,我建议用一个实现类似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处理第一次打电话


dav*_*dav 6

我认为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)