İşlevsel Programlama: eşzamanlılık ve durum hakkında doğru fikirler?


21

AP savunucuları eşzamanlılığın kolay olduğunu iddia ediyorlar çünkü paradigmaları değişmez durumdan kaçınıyor. Anlamadım.

Saf fonksiyonları ve değişmez veri yapılarını vurguladığımız FP kullanarak çok oyunculu bir zindan taraması (bir roguelike) yarattığımızı hayal edin. Odalar, koridorlar, kahramanlar, canavarlar ve ganimetlerden oluşan bir zindan üretiyoruz. Dünyamız etkili bir şekilde yapıların ve onların ilişkilerinin bir nesne grafiğidir. İşler değiştikçe dünyayı temsil etmemiz bu değişiklikleri yansıtacak şekilde değiştirilir. Kahramanımız bir fareyi öldürdü, bir şort kelimesi aldı.

Bana göre dünya (mevcut gerçeklik) bu devlet fikrini taşıyor ve FP'nin bunun üstesinden nasıl geldiğini özlüyorum. Kahramanımız harekete geçtikçe, işlevler dünyanın durumunu değiştirir. Her kararın (AI veya insan), şu anda olduğu gibi dünyanın durumuna dayanması gerektiği anlaşılıyor. Eşzamanlılık için nereye izin veririz? Dünyanın durumunu değiştiren eşzamanlı olarak birden fazla sürece sahip olamayız, ancak bir sürecin sonuçlarını süresi dolmuş bir devlete dayandırın. Tüm kontrolün tek bir kontrol döngüsü içinde gerçekleşmesi gerektiğini düşünüyor, böylece her zaman dünyanın mevcut nesne grafiğimiz tarafından temsil edilen mevcut durumu işliyoruz.

Açıkça, eşzamanlılık için tam olarak uygun durumlar vardır (yani, durumları birbirinden bağımsız olan yalıtılmış görevleri işlerken).

Eşzamanlılığın örneğimde ne kadar yararlı olduğunu göremiyorum ve sorun bu olabilir. Bir şekilde iddiayı yanlış beyan ediyor olabilirim.

Birisi bu iddiayı daha iyi temsil edebilir mi?


1
Paylaşılan duruma atıfta bulunuyorsunuz; paylaşılan durum her zaman olduğu gibi olacak ve her zaman bir senkronizasyon şekli gerektirecek, saf FP kullanıcıları arasında tercih edilen form STM'dir; koşullar otomatik olarak ele alınır. Paylaşılan hafızanın bir diğer tekniği, paylaşılan hafızanın yerine yerel hafızanın ve diğer aktörlerin yerel hafızasını isteyecek bilginin olduğu mesajların
iletilmesidir

1
Yani, paylaşılan durum eşzamanlılığının kolay olmasının tek iş parçacıklı bir uygulamada durumu yönetmeye nasıl yardımcı olduğunu soruyorsunuz? Öte yandan, örneğiniz açıkça bu şekilde uygulanmış olsun veya olmasın, kavramsal olarak eşzamanlılığa (her AI tarafından kontrol edilen varlık için bir konu) borç verir. Burada ne sorduğun kafam karıştı.
CA McCann

1
bir deyişle, Fermuarlar
jk.

2
Her nesnenin kendi dünya görüşü vardır. Sonunda tutarlılık olacak . Muhtemelen dalga fonksiyonunun çökmesi ile birlikte “gerçek dünyamızda” işler böyle yürüyor .
herzmeister,

1
"Tamamen işlevsel retrogames" oyununu
user802500

Yanıtlar:


15

Cevabını ima etmeye çalışacağım. Bu bir cevap değil , sadece tanıtım amaçlı bir örnek. @ jk'ın cevabı gerçek olanı gösteriyor fermuarlar.

Değişmez bir ağaç yapısına sahip olduğunuzu düşünün. Bir çocuk ekleyerek bir düğümü değiştirmek istiyorsunuz. Sonuç olarak, tamamen yeni bir ağaç elde edersiniz.

Ancak yeni ağacın çoğu yaşlı ağaçla tamamen aynıdır. Akıllıca bir uygulama , ağaç parçalarının çoğunu yeniden kullanır ve işaretçileri değiştirilmiş düğümün etrafına yönlendirir:

Vikipedi'den

Okasaki'nin kitabı bunun gibi örneklerle dolu.

Bu yüzden, oyun dünyanızın küçük parçalarının her hareketini (bozuk para topla) küçük bir kısmını değiştirebileceğinizi ve dünya veri yapınızın küçük parçalarını (madalyonun alındığı hücre) değiştirebildiğini farz ediyorum. Sadece geçmiş ülkelere ait olan kısımlar zamanla çöp toplanacaktır.

Bu, muhtemelen veri oyun dünyası yapısını uygun bir şekilde tasarlarken biraz dikkate alır. Ne yazık ki, bu konularda uzman değilim. Kesinlikle, değişken veri yapısı olarak kullanılabilecek NxM matrisinden başka bir şey olması gerekir. Muhtemelen ağaç düğümleri gibi birbirine işaret eden daha küçük parçalardan (koridorlar - ayrı hücreler?) Oluşmalıdır.


3
+1: Okasaki'nin kitabına işaret etmek için. Okumadım ama yapılacaklar listemde. Bence sizin tasvir ettiğiniz şey doğru çözüm. Alternatif olarak, benzersizlik türlerini göz önünde bulundurabilirsiniz (Clean, en.wikipedia.org/wiki/Uniqueness_type ): bu tür türleri kullanarak , başvuruda saydamlığı koruyarak veri nesnelerini yok edici şekilde güncelleyebilirsiniz.
Giorgio,

Anahtarlar veya kimlikler yoluyla dolaylı referans yoluyla tanımlanacak ilişkilerin bir faydası var mı? Yani, bir yapının diğerine daha az gerçek dokunuşunun, bir değişiklik meydana geldiğinde dünya yapısında daha az değişiklik yapılmasını gerektireceğini düşünüyordum. Yoksa bu teknik FP'de gerçekten kullanılmıyor mu?
Mario T. Lanza

9

9000'in cevabı cevabın yarısıdır, kalıcı veri yapıları değişmemiş parçaları tekrar kullanmanızı sağlar.

Ancak “hey, ağacın kökünü değiştirmek istersem ne olur?” Diyebilirsiniz. Verilen örnekle olduğu gibi şimdi tüm düğümleri değiştirmek anlamına gelir. Burası fermuarların kurtarmaya geldiği yer. Odaktaki öğenin O (1) 'de değiştirilmesine izin verir ve odak yapı içinde herhangi bir yere taşınabilir.

Fermuarlarla ilgili diğer nokta, istediğiniz veri türü için hemen hemen bir Fermuarın mevcut olmasıdır.


Ne yazık ki "fermuarlar" ı kazmak biraz zaman alacak, çünkü herhangi bir sadece FP'yi keşfeden saçaktayım. Haskell ile hiçbir deneyimim yok.
Mario T. Lanza

Bugün daha sonra bir örnek eklemeye çalışacağım
jk.

4

İşlevsel stil programları eşzamanlılığı kullanmak için bunun gibi birçok fırsat yaratır. Bir koleksiyonu dönüştürdüğünüzde veya filtrelendiğinizde veya topladığınızda ve her şey saf veya değişmez olduğunda, işlemin eşzamanlılık ile hızlandırılması için bir fırsat vardır.

Örneğin, AI kararlarını birbirinden bağımsız olarak ve belirli bir sırayla verdiğinizi varsayalım. Sırayla almazlar, hepsi aynı anda bir karar verir ve sonra dünya ilerle. Kod şöyle görünebilir:

func MakeMonsterDecision curWorldState monster =
    ...
    ...
    return monsterDecision

func NextWorldState curWorldState =
    ...
    let monsterMakeDecisionForCurrentState = MakeMonsterDecision curWorldState
    let monsterDecisions = List.map monsterMakeDecisionForCurrentState activeMonsters
    ...
    return newWorldState

Bir canavara bir dünya devletinde ne verileceğini hesaplayacak ve bir sonraki dünya devletini hesaplamanın bir parçası olarak her canavara uygulayacak bir işleve sahipsiniz. Bu, işlevsel bir dilde yapılması doğal bir şeydir ve derleyici paralel olarak 'her canavara uygula' adımında serbesttir.

Zorunlu bir dilde, etkilerini dünyaya uygulayarak her canavarın üzerinde yineleme yapma olasılığınız daha yüksek. Bu şekilde yapmak daha kolay çünkü klonlama veya karmaşık takma adlarla uğraşmak istemezsiniz. Bu durumda derleyici paralel hesaplamalar yapamaz , çünkü erken canavar kararları daha sonraki canavar kararlarını etkiler.


Bu biraz yardımcı olur. Bir oyunda, canavarların eşzamanlı olarak ne yapacaklarına karar vermelerine karar vermenin nasıl bir faydası olacağını görebiliyorum.
Mario T. Lanza

4

- Birkaç Zengin Hickey görüşmelere Dinleme bu bir özellikle - çelişkimi hafifletilebilir. Birinde, eşzamanlı işlemlerin en güncel duruma sahip olamayacağının doğru olduğunu belirtti. Bunu duymam gerekiyordu. Sindirimi zorlaştırmakta olduğum şey, programların aslında daha önce yenileri tarafından değiştirilmiş olan dünyanın anlık görüntülerine dayanan kararlara dayanarak tamam olacağıydı. Eşzamanlı FP'nin eski duruma dayanan kararlar konusunda nasıl bir sorun yaşadığını merak etmeye devam ettim.

Bir bankacılık uygulamasında, kararını o zamandan beri daha yeni bir kararla (geri çekilme meydana geldi) gerçekleşen bir devlet görüntüsüne dayandırmak istemeyiz.

Bu eşzamanlılık kolaydır, çünkü FP paradigması değişken durumdan kaçınır; kararları potansiyel olarak eski duruma dayandırmanın mantıksal değerleri hakkında bir şey söylemeye çalışmayan teknik bir iddiadır. FP hala sonuçta durum değişikliğini modeller. Bunun üstesinden gelmek yok.


0

AP savunucuları eşzamanlılığın kolay olduğunu iddia ediyorlar çünkü paradigmaları değişmez durumdan kaçınıyor. Anlamadım.

Bu genel soruyu, işlevsel bir neofit olan ancak yıllar içinde yan etkilerde gözlerime kalmış olan ve bunları daha kolay (ya da özellikle "daha güvenli" dahil olmak üzere her türlü nedenden dolayı hafifletmek isteyen biri olarak ele almak istedim. daha az hata eğilimli ") eşzamanlılık. İşlevsel eşlerime ve ne yaptıklarına bakarken, çim biraz daha yeşil görünüyor ve en azından bu konuda daha güzel kokuyor.

Seri Algoritmalar

Bununla birlikte, spesifik örneğinizle ilgili olarak, eğer probleminiz doğada seri ise ve B bitinceye kadar B uygulanamıyorsa, kavramsal olarak A ve B'yi ne olursa olsun paralel olarak çalıştıramazsınız. Eski oyun durumunu kullanarak paralel hamleler yapmayı temel alan cevabınızdeki sıra bağımlılığını kırmanın bir yolunu bulmanız veya diğer cevaplarda önerilen sıra bağımlılığını ortadan kaldırmak için parçalarının bağımsız olarak değiştirilmesine izin veren bir veri yapısı kullanmanız gerekir. veya bu tür bir şey. Fakat kesinlikle bunun gibi kavramsal tasarım problemlerinin bir payı var; burada her şeyi kolayca okulamazsınız çünkü işler değişmez. Bazı şeyler, mümkünse sipariş bağımlılığını kırmanın akıllıca bir yolunu bulana kadar doğada seri olacak.

Daha Kolay Eşzamanlılık

Yani, biz potansiyel olarak önemli ölçüde çünkü o ihtimali performansını iyileştirebilecek yerlerde yan etkileri dahil programları parallelize başarısız birçok durumlar vardır, adı geçen olabilir parçacığı güvenli olmayabilir. Değişebilir durumun (veya daha spesifik olarak dış yan etkilerin) ortadan kaldırılmasının, "kesinlikle diş güvenli" haline getirdiği "diş ipliği güvenli" olabileceği veya döndüğü gibi olduğunu gördüğüm kadarıyla çok yardımcı olur .

Bu ifadeyi biraz daha somutlaştırmak için, size bir karşılaştırıcıyı kabul eden ve bunu bir dizi öğeyi sıralamak için kullanan bir sıralama işlevini uygulamak için bir görev verdiğimi düşünün. Oldukça genel hale getirilmek isteniyor ancak size, her zaman çok iş parçacıklı bir uygulama kullanmanın şüphesiz fayda sağlayacağı gibi bir ölçekte (milyonlarca öğe veya daha fazla öğenin) girdilerine karşı kullanılacağı konusunda kolay bir varsayım vereceğim. Sıralama fonksiyonunuzu çok okuyabilir misiniz?

Sorun, sıralama işlevinizin çağırdığı karşılaştırıcılar olabilir;Fonksiyonu dejeneralize etmeden imkansız olan tüm olası durumlar için nasıl uygulandığını (veya en azından belgelendirildiğini) bilmiyorsanız yan etkilere neden olabilirsiniz. Bir karşılaştırıcı, atomik olmayan bir şekilde içindeki bir global değişkeni değiştirmek gibi iğrenç bir şey yapabilir. Karşılaştırıcıların% 99,9999'u bunu yapamayabilir, ancak bu genelleştirilmiş işlevi, yalnızca yan etkilere neden olabilecek vakaların% 0,00001'i nedeniyle hala okuyamıyoruz. Sonuç olarak, hem tek iş parçacıklı hem de çok iş parçacıklı sıralama işlevi sunmanız ve sorumluluğu iş parçacığı güvenliğine dayanarak hangisini kullanacağınıza karar vermek için bunu kullanan programcılara vermeniz gerekebilir. İnsanlar hala tek parçalı sürümü kullanabilir ve çoklu okuma fırsatlarını kaçırırlar, çünkü karşılaştırıcının iş parçacığının güvenli olup olmadığından emin olmayabilirler.

İşlevlerin şimdi ve gelecek için yan etkilere neden olmayacağına dair kesin güvencemiz varsa, her yere kilit atmadan işlerin iplik güvenliği ile ilgili rasyonelleştirmeye dahil olabilecek bir sürü beyin gücü var. Ve korku var: pratik korku, çünkü bir yarış koşulunu birkaç kez çok fazla zorlamak zorunda kalan herkes,% 110 olamayacağından emin olamayacağından ve bu konuda yaşayacağından emin olamayacağınız konusunda çok tereddütlü olabilir. En paranoyak bile (ki muhtemelen en azından sınırda olduğum), saf işlev güvenle paralel olarak adlandırabileceğimiz rahatlama ve güven duygusunu sağlar.

Ve bu işlevlerin saf işlevsel dillerle elde edeceğiniz iplik güvenliği olduğuna dair sert bir garanti alabiliyorsanız, bunu çok faydalı bulduğum ana durumlardan biri. Diğeri, işlevsel dillerin çoğu zaman, her şeyden önce yan etkileri olmayan işlevler oluşturmayı teşvik etmesidir. Örneğin, size büyük bir veri yapısı girmenin oldukça verimli olduğu kalıcı veri yapıları sağlayabilir ve daha sonra orijinalinden dokunmadan orijinalinden sadece küçük bir kısmı değiştirildikten sonra yepyeni bir ürün çıkartabilirler. Bu tür veri yapıları olmadan çalışanlar, onları doğrudan değiştirmek ve yol boyunca bazı iplik güvenliğini kaybetmek isteyebilirler.

Yan etkiler

Bu, (arkadaşlarımın süper havalı olduğunu düşündüğüm) fonksiyonel arkadaşlarıma saygımdan dolayı bir kısmına katılmıyorum:

[...] çünkü paradigmaları değişken durumlardan kaçınır.

Eşzamanlılığı gördüğüm kadar pratik kılan, mutlaka değişmezlik değildir. Yan etkilere neden olmayan fonksiyonlar. Bir işlev sıralamak için bir dizi girerse, kopyalar ve ardından içeriğini sıralamak için kopyayı mutasyona uğratır ve kopyayı çıktılarsa, aynı girdiyi geçseniz bile, bazı değişken dizi türleriyle çalışan bir iş parçacığı kadar güvenli Birden fazla iş parçacığından diziye. Bu yüzden, çok eşzamanlılık dostu kod oluşturmada hala değişebilir türler için bir yer olduğunu düşünüyorum. Yani, değişmez özellikleri için değil, çok fazla kullandığım kalıcı veri yapıları dahil olmak üzere değişmez türlere ek yararlar sağlamasına rağmen Yan etkileri olmayan fonksiyonlar yaratmak için herşeyi derinlemesine kopyalamak zorunda kalmazsınız.

Sık sık, bazı ek verileri, belki de ekstra bir dolaylı seviyeyi ve kalıcı bir veri yapısının bölümleri üzerine muhtemelen bazı GC'leri kopyalamak ve kopyalamak şeklinde işlevler yapmaktan başka bir şey yapmazsınız; 32 çekirdekli bir makine ve paralel olarak daha fazla şey yapabilirsek, değişimin muhtemelen buna değer olduğunu düşünüyorum.


1
“Değişken devlet” her zaman prosedür düzeyinde değil uygulama düzeyinde durum anlamına gelir. İşaretçilerin giderilmesi ve parametrelerin kopya değerleri olarak geçirilmesi FP'de pişirilen tekniklerden biridir. Ama her kullanışlı fonksiyon olarak mutasyon durumuna sahip bazı seviyede - fonksiyonel programlamanın noktası prosedürünü girmezse arayana ait olduğu kesilebilir devlet sağlamaktır ve mutasyonlar dönüş değerleri dışında prosedürü çıkmak yok! Ancak, devleti mutasyona uğramadan çok fazla iş yapabilen çok az program vardır ve hatalar arayüzde tekrar ortaya çıkar.
Steve

1
Dürüst olmak gerekirse, çoğu modern dil işlevsel bir programlama stilinin kullanılmasına izin verir (biraz disiplin ile) ve elbette fonksiyonel kalıplara adanmış diller vardır. Ancak, daha az hesaplama açısından verimli bir kalıptır ve popüler olarak nesne yönelimi 90'larda olduğu gibi tüm hastalıklar için bir çözüm olarak aşırı hiperdir. Programların çoğu, paralelleştirmeden faydalanacak CPU yoğun hesaplamalara bağlı değildir ve bu programların programın paralel yürütmeye uygun bir şekilde düşünülmesi, tasarlanması ve uygulanması zorluğundan kaynaklanır.
Steve

1
Değişken durumla ilgilenen çoğu program bunu yapar, çünkü bir nedenden ötürü yapmak zorundadırlar. Ve çoğu program hatalı değil çünkü paylaşılan durumu kullanıyor veya anormal bir şekilde güncelliyorlar - genellikle girdi olarak beklenmeyen çöp aldıkları için (bu bir çöp çıktısını belirler) ya da girdilerinde yanlış çalıştıklarından (amaç anlamında yanlış) elde edilecek). İşlevsel kalıplar bunu ele almak için çok az şey yapar.
Steve

1
@Steve C ya da C ++ gibi dillerden işleri daha güvenli bir şekilde yapmanın yollarını araştırmanın bu tarafında olduğum için sizinle en azından yarı yolda hemfikir olabilirim ve gerçekten tam olarak gitmemiz gerektiğini düşünmüyorum -Bunu yapmak için saf işlevsel şişirilmiş. Fakat en azından FP'de bazı kavramları faydalı buluyorum. Ben sadece burada PDS'yi nasıl faydalı bulduğuma dair bir cevap yazdım ve PDS ile ilgili bulduğum en büyük yarar aslında iş güvenliği değil, instancing, tahribatsız kurgu, istisna güvenliği, basit geri alma, vb.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.