Волокна против явных счетчиков

Я играю с Ruby, чтобы выучить язык. В настоящее время я пытаюсь обдумать концепцию волокон. Согласно этому ответу, они довольно часто используются для создания (бесконечных) внешних счетчиков. С другой стороны, кажется, что это пересекается с концепцией так называемых явных счетчиков.

Скажем, я хочу написать фрагмент кода, который запускает последовательные простые числа (да, следующий алгоритм имеет время выполнения O (страшно)). Я могу реализовать это с помощью волокон:

prime_fiber = Fiber.new do
    primes = [2]
    Fiber.yield 2
    current = 1
    loop do
        current += 2 
        unless primes.find {|value| (current % value) == 0}
            Fiber.yield current
            primes << current
        end
    end
end

ARGV[0].to_i.times {print "#{prime_fiber.resume}, "}

Это не создает объект перечислителя сам по себе, хотя создать его из него несложно. Напротив, я также могу использовать явно определенный перечислитель, который имеет дополнительное преимущество, поскольку он уже является объектом перечислителя:

prime_enum = Enumerator.new do |yielder|
    primes = [2]
    yielder.yield 2
    current = 1 
    loop do
        current += 2
        unless primes.find {|value| (current % value) == 0}
            yielder.yield current
            primes << current
        end
    end
end

ARGV[0].to_i.times {print "#{prime_enum.next}, "}
# I could also write:
# p prime_enum.first(ARGV[0].to_i)

Оба метода позволяют мне реализовать какие-то сопрограммы, и они кажутся мне взаимозаменяемыми. Итак, когда я предпочитаю одно другому? Существует ли общепринятая практика? Мне трудно уложить в голове все эти идиомы, поэтому заранее извиняюсь, если это сочтут глупым вопросом.


person Tunix    schedule 20.09.2013    source источник


Ответы (1)


Я бы использовал Enumerator, это позволяет вам использовать take, take_while и даже each, если ваша последовательность конечна. В то время как Fiber предназначен для легкого параллелизма и довольно ограничен в качестве перечислителя.

prime_enum.take(ARGV[0].to_i).each { |x| puts x }

or

prime_enum.take_while { |x| x < ARGV[0].to_i }.each { |x| puts x }
person Victor Moroz    schedule 21.09.2013
comment
Итак, я полагаю, что перечислители рекомендуются, если требуются простые последовательности значений, и что мне следует использовать волокна, если я хочу подчеркнуть аспект параллелизма в моем коде. - person Tunix; 22.09.2013