SORU
29 Ocak 2012, Pazar


Neden lifleri ihtiyacımız var

Klasik bir örnek var Elyaflar için: Fibonacci sayıları oluşturuluyor

fib = Fiber.new do  
  x, y = 0, 1 
  loop do  
    Fiber.yield y 
    x,y = y,x y 
  end 
end

Neden Lifleri burada ihtiyacımız var mı? Sadece aynı Proc (kapatma, aslında bu yeniden yazabilirim

def clsr
  x, y = 0, 1
  Proc.new do
    x, y = y, x   y
    x
  end
end

Bu yüzden

10.times { puts fib.resume }

ve

prc = clsr 
10.times { puts prc.call }

sadece aynı sonucu döndürecektir.

Lifler avantajları vardır. Lifler ile yazabilirim ne Lambda ve diğer serin Ruby özellikleri ile yapamam?

CEVAP
8 ŞUBAT 2012, ÇARŞAMBA


Lifler muhtemelen asla doğrudan düzey bir uygulama kod içerisinde kullanılacak bir şey. Daha sonra yüksek düzey kodu kullanan diğer soyutlamalar oluşturmak için kullanabileceğiniz bir akış-kontrol ilkel.

Muhtemelen Ruby liflerin #1 kullanımı Ruby 1.9 çekirdek Ruby bir sınıf olan Enumerators, uygulamaktır. Buinanılmazyararlı.

Ruby 1.9, çekirdek sınıfları neredeyse herhangi bir yineleyici yöntemi ararsanolmadanbir blok geçirilmesi, Enumerator dönecektir.

irb(main):001:0> [1,2,3].reverse_each
=> #<Enumerator: [1, 2, 3]:reverse_each>
irb(main):002:0> "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):003:0> 1.upto(10)
=> #<Enumerator: 1:upto(10)>

Enumerators Bu Sayısız nesneler ve each kendi yöntemleri ile blok çağrılmıştı özgün yineleyici yöntemi ile elde edilmiş olan element verim. Verdiğim örnekte, Numaralandırıcısı reverse_each tarafından döndürülen 3,2,1 veren each bir yöntemi vardır. Numaralandırıcısı chars verimleri tarafından döndürülen "c","b","" (ve benzeri). AMA, orijinal yineleyici yöntemi aksine, Numaralandırıcısı ayrıca eğer next ararsan bir tek arda: elemanları dönebilirsiniz

irb(main):001:0> e = "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):002:0> e.next
=> "a"
irb(main):003:0> e.next
=> "b"
irb(main):004:0> e.next
=> "c"

Duymuş olabilirsiniz, "iç kullanımına" ve "(her ikisi de iyi bir açıklama" Gang of Four "Tasarım Desenleri kitap). verilen" dış kullanımına Yukarıdaki örnek Sıralayıcısını bir dış bir iç yineleyici açmak için kullanılabilir olduğunu gösterir.

Bu kendi sıralayıcısını yapmak için bir yoldur:

class SomeClass
  def an_iterator
    # note the 'return enum_for...' pattern; it's very useful
    # enum_for is an Object method
    # so even for iterators which don't return an Enumerator when called
    #   with no block, you can easily get one by calling 'enum_for'
    return enum_for(:an_iterator) if not block_given?
    yield 1
    yield 2
    yield 3
  end
end

Deneyelim:

e = SomeClass.new.an_iterator
e.next  # => 1
e.next  # => 2
e.next  # => 3

Bir dakika... garip bir şey var gibi görünüyor mu? Düz çizgi kod olarak an_iterator 27 *ifadeleri yazdı, ama Numaralandırıcısı onları çalıştırabilirsinizbir defada bir. next, an_iterator yürütme çağrılar arasında"". dondurulmuş Her zaman yield aşağıdaki açıklamaya çalışan bir aşağı devam eder, ve sonra "" tekrar. donuyor next, çağrı

Bu nasıl uygulandığını tahmin edebilir misiniz? Numaralandırıcısı bir lif an_iterator çağrısı sarar, ve bir blok geçiriraskıya lif. Her zaman an_iterator blok verir, çalışır durumda olan fiber askıya alınır, ve yürütme ana konu üzerinde devam ediyor. Bir dahaki sefere 35**, fiber kontrol geçer, diyorsunuzblok döndürürkaldığı yerden , ve an_iterator devam ediyor.

Lifler olmadan bunu yapmak için gerekli ne olacağını düşünmek öğretici olacaktır. Hem iç hem de dış kullanımına sunmak istedim olan HER sınıf açık kod next çağrılar arasında durumunu izlemek için içerir. Sonraki her arama bu durumu kontrol edin ve değeri iade etmeden önce güncelleme gerekiyor. Lifler ile yapabilirizotomatik olarakbir dış bir iç yineleyici dönüştürmek.

Bu mecbur değil ile lifler persay, ama bana söz bir şey daha yap Sıralayıcısını: izin sizin için geçerli üst düzey Sayısız yöntemleri için diğer kullanımına dışında each. Düşünün: normalde tüm Sayısız yöntemleri, map, select, include?, inject, ve benzeri dahil olmak üzeretümelemanları each tarafından bulunmuştur çalışın. Ama eğer bir nesne each diğer dışında kullanımına varsa?

irb(main):001:0> "Hello".chars.select { |c| c =~ /[A-Z]/ }
=> ["H"]
irb(main):002:0> "Hello".bytes.sort
=> [72, 101, 108, 108, 111]

Herhangi bir engelleme ile yineleyici çağıran bir Numaralandırma döndürür, ve sonra diğer Sayısız yöntemleri çağırabilir.

Geri lifleri, Sayısız take yöntemi kullandınız mı?

class InfiniteSeries
  include Enumerable
  def each
    i = 0
    loop { yield(i  = 1) }
  end
end

Eğer bir şey each bu yöntem ararsa, asla dönmek gerekir gibi görünüyor? Şuna bir bak:

InfiniteSeries.new.take(10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Eğer bu başlık altında lifleri kullanır mı bilmiyorum, ama olabilir. Lifler bir dizi sonsuz listeleri ve tembel değerlendirme uygulamak için kullanılabilir. Bazı tembel yöntemleri örnek Sıralayıcısını ile tanımlanan, bazı burada tanımlıyorum: https://github.com/alexdowad/showcase/blob/master/ruby-core/collections.rb

Ayrıca genel amaçlı coroutine bir tesis lifleri kullanarak inşa edebilirsiniz. Henüz hiç benim programları coroutines kullandım ama bilmek güzel bir konsept.

Bu olasılıklar hakkında bir fikir verir umarım. Başta da dediğim gibi, lifler düşük seviyeli bir akış-kontrol ilkel. Mümkün kontrol-akış "" programı ("yer imleri" bir kitap) sayfalarında ve onları istediğiniz gibi. farklı pozisyonlar arasında geçiş gibi içinde birden fazla korumak için yapıyorlar Beri keyfi kod çalıştırmak bir lif, diyebilirsin içine 3. taraf kod üzerinde bir elyaf, ve sonra "freeze" ve devam ediyor, başka bir şey ne zaman geri arar kodunu kontrol.

Şöyle bir şey düşünün: birçok müşteri hizmet edecek. sunucu bir program yazıyoruz Bir istemci ile tam bir etkileşim bir dizi adım gitmektir, ama her bağlantı geçici ve bağlantıları arasında her istemci için devlet hatırlamak zorunda. (Web programlama gibi geliyor mu?)

Açıkça bu durumu saklamak, ve bir istemci bağlandığında her zaman kontrol etmek yerine ("adım" yapmak zorundalar), her müşteri için bir lif sağlamak. bir sonraki ne olduğunu görmek için İstemci belirledikten sonra, lif ve yeniden başlamak onların almak istiyorsunuz. Daha sonra her bağlantı sonunda, fiber askıya almak ve tekrar saklamak istiyorsunuz. Bu yol, düz çizgi kod tam bir etkileşim, tüm adımları dahil olmak üzere tüm mantığı doğal olarak program yerel olarak çalıştırmak için yapıldı gibi () uygulamak yazabilirsiniz.

Böyle bir şey pratik (en azından şimdilik) olmayabilir birçok nedeni var eminim, ama yine sadece bazı olasılıklar göstermeye çalışıyorum. ; Kavramı olsun, hiç kimse düşünmüş Henüz tamamen yeni Bazı uygulama ile gelebilir kim bilir!

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • HouseholdHacker

    HouseholdHac

    6 Kasım 2007
  • NextKsa

    NextKsa

    7 EKİM 2009
  • Xbox

    Xbox

    1 Kasım 2005