Olay odaklı bir mimaride ilk durum nasıl ele alınır?


33

Bir de olay kaynaklı mimari bir olay sistemi üzerinden gönderildiğinde her bir bileşeni sadece hareket eder.

Fren pedalına ve fren lambasına sahip bir varsayımsal otomobil hayal edin.

  • Fren lambası dönüşler üzerinde bir aldığında brake_on , olay ve kapalı bir aldığında brake_off olayı.
  • Fren pedalı bir gönderir brake_on aşağı basıldığında olayı ve brake_off yayımlandıktan olayı.

Otomobilin fren pedalı basılı durumdayken açık olduğu duruma gelinceye kadar bu her şey yolunda ve güzel . Fren lambası hiçbir zaman bir brak__ olayı almadığı için uzak durur - açıkça istenmeyen bir durumdur. Fren lambasını varsayılan olarak açmak sadece durumu tersine çevirir.

Bu 'başlangıç ​​durumu' sorununu çözmek için ne yapılabilir?

EDIT: Tüm cevaplar için teşekkür ederim. Benim sorum gerçek bir araba hakkında değildi. Otomobillerde sürekli olarak devleti göndererek bu sorunu çözdüler - bu nedenle o alanda herhangi bir başlangıç ​​sorunu yok. Yazılım alanımda, bu çözüm birçok gereksiz CPU döngüsü kullanacaktı .

2 EDIT: @ gbjbaanb'ın cevabına ek olarak , hangi bir sistem için gidiyorum:

  • varsayımsal fren pedalı, başlattıktan sonra durumu ile ilgili bir olay gönderir ve
  • Varsayımsal fren lambası, başlattıktan sonra, fren pedalından bir durum olayı isteyen bir olay gönderir.

Bu çözümle, bileşenler arasında bağımlılık yok, yarış koşulları yok, bayatlayacak mesaj kuyrukları yok ve 'ana' bileşenler yok.


2
Akla gelen ilk şey initialize, ihtiyaç duyulan sensör verilerini içeren bir "sentetik" olay oluşturmak (onu çağırmak ).
msn

Pedal bir brake_pedal_on olayı göndermeli ve gerçek fren brake_on olayı göndermeli mi? Fren çalışmıyorsa fren lambamın yanmasını istemem.
bdsl

3
Varsayımsal bir örnek olduğunu söylemiş miydim? :-) Soruyu kısa ve noktaya getirmek oldukça basittir.
Frank Kusters

Yanıtlar:


32

Bunu yapmanın birçok yolu var, ancak mesaj tabanlı bir sistemi mümkün olduğunca ayrık tutmayı tercih ediyorum. Bu, genel sistemin herhangi bir bileşenin durumunu okuyamayacağı veya herhangi bir bileşenin başka birinin durumunu okuyamayacağı anlamına gelir (bu şekilde bağımlılığın spagetti bağları yatıyor).

Bu nedenle, çalışan sistem kendi kendine bakacak olsa da, her bileşene kendisini başlatmasını söyleyecek bir yola ihtiyacımız var ve bileşen kaydında zaten böyle bir şey var, yani başlangıçta çekirdek sistemin her bileşene bilgi vermesi gerekiyor. şimdi kaydedilmiştir (ya da her bir bileşenden ayrıntılarını iade etmesi için kayıt olmasını isteyecektir). Bu, bileşenin başlangıç ​​görevlerini yerine getirebildiği ve normal işletimde olduğu gibi iletiler gönderebildiği aşamadır.

Böylece, kontak başlatıldığında, fren pedalı, araç yönetiminden bir kayıt / kontrol mesajı alacak ve yalnızca "Burada ve çalışıyorum" mesajını döndürmeyecek, sonra kendi durumunu kontrol edip gönderecek bu durum için mesajlar (örneğin, bir pedal basılı mesajı).

Sorun daha sonra başlangıçtaki bağımlılıklardan biri haline gelir, sanki fren lambası henüz kaydedilmemiş gibi, o zaman mesajı alamaz, ancak çekirdek sistem başlatma, kayıt etme ve kontrol rutinini tamamlayana kadar tüm bu mesajları sıraya sokarak kolayca çözülür. .

En büyük yararı, baştan başlatmak için özel bir kodun gerekmediğinden, zaten yazmak zorunda olmanız dışında (tamam, eğer fren pedalı olayları için gönderdiğiniz mesajlar bir fren pedalı işleyicisindeyse) , ancak bu kodu işleyici mantığına yoğun bir şekilde bağladıysanız ve bir başkasına zaten normal olarak gönderdiklerinin dışında bileşenler arasında etkileşim olmadıkça, bu genellikle bir sorun değildir. Bu yüzden mesaj ileten mimariler çok iyi!


1
Cevabını seviyorum, çünkü tüm bileşenleri ayrı tutuyor - bu mimariyi seçmenin en önemli nedeni buydu. Bununla birlikte, şu anda sistemin 'başlatılmış' durumda olduğuna karar veren gerçek bir 'ana' bileşen yoktur - her şey çalışmaya başlar. Sonuç olarak benim sorunumda sorun var. Master sistemin çalıştığına karar verdiğinde, tüm bileşenlere bir 'sistem başlatıldı' olayı gönderebilir ve ardından her bileşen kendi durumunu yayınlamaya başlar. Sorun çözüldü. Teşekkür ederim! (Şimdi sadece sistemin başlatılıp başlatılmadığına nasıl karar vereceğimizle ilgili sorunum kaldı ...)
Frank Kusters

Durum güncelleme göndericisinin, her bir nesneden alınan en yeni güncellemeleri takip etmesine ve yeni bir abonelik isteği alındığında, yeni aboneye kayıtlı etkinlik kaynaklarından aldığı en yeni güncellemeleri göndermesine ne dersiniz?
Supercat

Bu durumda, olayların ne zaman sona erdiğini de takip etmeniz gerekir. Tüm olaylar, kayıt olabilecek herhangi bir yeni bileşen için sonsuza kadar bekletilemez.
Frank Kusters

@spaceknarf peki, "her şey yoluna girmeye başlar" durumunda bileşenlere bağımlılık kuramazsınız, böylece pedal ışıktan sonra başlar, onları bir sırayla çalıştırmaya başladığınızı hayal etsem de, o sırada koşma Bunları 'doğru' sırayla (örn. linux startup init komut dosyası, ilk önce başlatılacak olan hizmetin 1.xxx ve 2. adının 2.xxx vb.
gbjbaanb

Bunun gibi bir düzende betikler kırılgan. Çok fazla örtük bağımlılık içerir. Bunun yerine, çalışması gereken statik olarak yapılandırılmış bir bileşen listesine sahip (@Lie Ryan tarafından belirtildiği gibi) bir 'ana' bileşeniniz varsa, o zaman tüm bu bileşenler yüklendiğinde bir 'hazır' olayı yayınlayabilir. Buna cevaben, tüm bileşenler başlangıç ​​durumlarını yayınlar.
Frank Kusters

4

Yük / başlatma sırasında durumları uygun şekilde ayarlayan bir initialize olayına sahip olabilirsiniz. Bu, birden fazla donanım parçası içermeyen basit sistemler veya programlar için arzu edilebilir, ancak çoklu başlatma bileşenleriyle daha karmaşık olan sistemler için, hiçbir şekilde başlatmama riskiyle aynı - yani bir "fren açık" olayı kaçırılır veya iletişiminiz boyunca kaybolursa sistemi (örneğin, CAN tabanlı bir sistem) yanlışlıkla sisteminizi frene basılmış gibi başlatmış gibi geriye doğru ayarlayabilirsiniz. Bir araba gibi, sahip olabileceğiniz daha fazla kontrolör, bir şeylerin kaçırılma olasılığı artar.

Bunu hesaba katmak için, "fren açık" mantığına tekrar tekrar "fren açık" olayları gönderebilirsiniz. Belki her 1/100 saniye veya bir şey. Beyni içeren kodunuz bu olayları dinleyebilir ve onları alırken “freni açmayı” tetikleyebilir. "Fren açık" sinyallerinin alınmadığı 1/10 saniye sonra, dahili bir "brake_off" olayı tetikler.

Farklı olayların oldukça farklı zamanlama gereksinimleri olacaktır. Bir otomobilde, fren lambanızın çek yakıt ışığından (bir çoklu saniye gecikmesinin muhtemelen kabul edilebilir olduğu yerlerde ) veya diğer daha az önemli sistemlerde olduğundan daha hızlı olması gerekir .

Fiziksel sisteminizin karmaşıklığı, bu yaklaşımlardan hangisinin daha uygun olduğunu belirleyecektir. Örneği bir araç olduğu göz önüne alındığında, muhtemelen ikincisine benzer bir şey istersiniz.

Her iki durumda da, fiziksel bir sistemde, doğru bir şekilde alınmakta / işlenmekte tek bir olaya güvenmek istemezsiniz. Ağa bağlı bir sistemdeki bağlı mikro denetleyiciler genellikle bu nedenle "Ben yaşıyorum" zaman aşımına sahiptir.


Fiziksel bir sistemde bir kabloyu çalıştırır ve ikili mantığı kullanırsınız: YÜKSEK, fren basılı ve DÜŞÜK, fren basılı değil
kilit manyağı,

@ ratchetfreak, bu tür şeyler için birçok imkan var. Belki bir anahtar bununla baş edebilir. Basitçe ele alınmayan bir çok sistem olayı var .
enderland

1

Bu durumda, freni basit bir açma / kapama olarak modellemezdim. Aksine, "fren basıncı" olayları gönderirdim. Örneğin, 0 basıncı kapalı olduğunu gösterir ve 100 basıncı tamamen basılır. Sistem (düğüm) gerektiğinde kontrolör (ler) e sürekli olarak mola basıncı olayları (belirli bir aralıkta) gönderir.

Sistem başlatıldığında, kapatılana kadar basınç olayları almaya başlayacaktır.


1

Durum bilgisini aktarmanın tek yolu olaylardan geçiyorsa, başınız derde girer. Bunun yerine, ikisine birden sahip olmanız gerekir:

  1. Fren pedalının güncel durumunu sorgulamak ve
  2. Fren pedalındaki "durum değişti" olaylarını kaydedin.

Fren lambası, fren pedalının bir gözlemcisi olarak görülebilir. Başka bir deyişle, fren pedalı fren lambası hakkında hiçbir şey bilmez ve onsuz da çalışabilir. (Bu, fren pedalına proaktif olarak "ilk durum" olayı gönderen herhangi bir fren pedalı kavramının kötü bir şekilde tasarlandığı anlamına gelir.)

Sistem başlatıldığında, fren lambası fren bildirimlerini almak için fren pedalına kaydolur ve ayrıca fren pedalının o anki durumunu okur ve kendini açar veya kapatır.

Ardından, fren bildirimleri üç yoldan biriyle uygulanabilir:

  1. parametresiz "fren pedalı durumu değişti" olayları olarak
  2. "fren pedalı şimdi basıldı" ve "şimdi fren pedalı bırakıldı" olayları olarak
  3. "basılı" veya "serbest bırakılmış" parametresiyle "yeni fren pedalı durumu" olayı olarak.

İlk yaklaşımı tercih ediyorum, bu, bildirimi aldıktan sonra, fren lambasının basitçe yapmayı bildiği şeyi yapacağını gösteriyor: fren pedalının mevcut durumunu okumak ve kendini açmak veya kapatmak.


0

Olay güdümlü bir sistemde (şu an kullanıyorum ve seviyorum), olayları olabildiğince ayrı tutmanın önemli olduğunu düşünüyorum. Bu düşünceyi aklımda tutalım, hadi hemen girelim.

Bazı varsayılan durumların olması önemlidir. Fren lambanız varsayılan 'kapalı' durumunu alacaktır ve fren pedalınız varsayılan 'yukarı' halini alacaktır. Bundan sonra yapılacak herhangi bir değişiklik bir olay olur.

Şimdi sorunuzu ele almak. Fren pedalınızın başlatıldığını ve basılı tutulduğunu, olay patladığını, ancak olayı almak için henüz fren lambasının olmadığını hayal edin. Herhangi bir mantığı başlatmadan önce nesnelerin oluşturulmasını (olay dinleyicilerinin başlatılacağı yer) ayrı bir adım olarak ayırmanın en kolay olduğunu buldum . Bu, tanımladığınız herhangi bir yarış koşulunu önleyecektir.

Aynı zamanda, etkili bir şekilde aynı olan şey için iki farklı olay kullanmayı da zor buluyorum . brake_offve bir parametre ile brake_onbasitleştirilebilir . Destekleyici veriler ekleyerek etkinliklerinizi bu şekilde basitleştirebilirsiniz.e_brakebool on


0

İhtiyacınız olan bir yayın olayı ve mesaj gelen kutuları. Bir yayın, belirtilmemiş sayıda dinleyicide yayınlanan bir mesajdır. Bir bileşen yayın olaylarına abone olabilir, böylece yalnızca ilgilendiği olayları alır. Gönderenin alıcılarının kim olduğunu bilmesi gerekmediğinden bu ayrıştırmayı sağlar. Abonelik tablosunun bileşen kurulumu sırasında statik olarak yapılandırılması gerekir (başlatıldığı zaman yerine). Gelen kutusu, hedef bileşen çevrimdışı olduğunda mesajları tutmak için arabellek görevi gören mesaj yönlendiricisinin bir parçasıdır.

Faturaları kullanmak, gelen kutusu boyutunda olan bir sorunu getirir. Sistemin artık çevrimiçi olamayacak olan bileşenler için gittikçe artan sayıda iletiyi saklamak zorunda kalmasını istemiyorsunuz. Bu, özellikle katı bellek kısıtlı gömülü sistemlerde önemlidir. Gelen kutusu boyut sınırının üstesinden gelmek için, yayınlanan tüm iletilerin birkaç kurala uyması gerekir. Kurallar:

  1. Her yayın etkinliği bir isim gerektirir
  2. herhangi bir zamanda, bir yayın etkinliği göndereni, belirtilen ada sahip yalnızca bir etkin yayını içerebilir
  3. olayın neden olduğu etki önemsiz olmalıdır

Yayın adı, bileşen yükleme süresi boyunca bildirilmelidir. Bir bileşen, alıcı öncekini işlemeden önce aynı adla ikinci bir yayın gönderirse, yeni yayın öncekinin üzerine yazar. Artık, belirli bir boyutu asla aşmayacağı garanti edilebilecek ve abonelik tablolarına göre önceden hesaplanabilecek bir statik gelen kutusu boyut sınırına sahip olabilirsiniz.

Son olarak, bir yayın arşivine de ihtiyacınız var. Yayın arşivi, her yayın adından son olayı tutan bir tablodur. Yeni kurulan bileşenler, gelen kutusunda yayın arşivindeki iletilerle önceden doldurulmuş olacak. Gelen kutusundaki gibi, yayın arşivi de statik boyutta olabilir.

Ek olarak, mesaj yönlendiricisinin kendisinin çevrimdışı olduğu durumlarla başa çıkmak için ayrıca mesaj giden kutularına ihtiyacınız vardır. Mesaj giden kutusu, giden mesajı geçici olarak tutan bileşenin bir parçasıdır.

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.