C # olayları eşzamanlı mı?


104

Bu sorunun iki bölümü var:

  1. Bir olayın yükseltilmesi iş parçacığını engelliyor mu , yoksa EventHandlers'ın eşzamansız olarak yürütülmesini mi başlatıyor ve iş parçacığı aynı anda devam ediyor mu?

  2. Are bireysel EventHandlers eşzamanlı arkaya çalıştırın (olayına abone) ya da başkalarının aynı anda çalışan olmadığını hiçbir garantisi ile uyumsuz çalışacak mı?

Yanıtlar:


37

Sorularınızı cevaplamak için:

  1. Olay işleyicilerinin tümü eşzamanlı olarak uygulanıyorsa, bir olayın başlatılması iş parçacığını engeller.
  2. Olay işleyicileri, olaya abone oldukları sırada birbiri ardına yürütülür.

Ben de iç mekanizması eventve bununla ilgili işlemleri merak ediyordum . Bu yüzden basit bir program yazdım ildasmve uygulanmasının etrafından dolaşıyordum.

Kısa cevap

  • olaylara abone olma veya olayları çağırma ile ilgili hiçbir zaman uyumsuz işlem yoktur.
  • olay, aynı delege türündeki bir destek delege alanıyla uygulanır
  • abone olmak ile yapılır Delegate.Combine()
  • abonelik iptali ile yapılır Delegate.Remove()
  • Çağırma, yalnızca son birleşik delegeyi çağırarak yapılır.

İşte yaptığım şey. Kullandığım program:

public class Foo
{
    // cool, it can return a value! which value it returns if there're multiple 
    // subscribers? answer (by trying): the last subscriber.
    public event Func<int, string> OnCall;
    private int val = 1;

    public void Do()
    {
        if (OnCall != null) 
        {
            var res = OnCall(val++);
            Console.WriteLine($"publisher got back a {res}");
        }
    }
}

public class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();

        foo.OnCall += i =>
        {
            Console.WriteLine($"sub2: I've got a {i}");
            return "sub2";
        };

        foo.OnCall += i =>
        {
            Console.WriteLine($"sub1: I've got a {i}");
            return "sub1";
        };

        foo.Do();
        foo.Do();
    }
}

İşte Foo'nun uygulaması:

görüntü açıklamasını buraya girin

Bir alan OnCall ve bir olay olduğunu unutmayın OnCall . Alan OnCall, kesinlikle destekleyici mülktür. Ve bu sadece bir Func<int, string>, burada süslü değil.

Şimdi ilginç kısımlar:

  • add_OnCall(Func<int, string>)
  • remove_OnCall(Func<int, string>)
  • ve nasıl OnCallçağrılırDo()

Abone Olma ve Aboneliği İptal Etme Nasıl Uygulanır?

İşte add_OnCallCIL'deki kısaltılmış uygulama. İlginç olan kısım, Delegate.Combineiki delegeyi birleştirmek için kullanmasıdır .

.method public hidebysig specialname instance void 
        add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
  // ...
  .locals init (class [mscorlib]System.Func`2<int32,string> V_0,
           class [mscorlib]System.Func`2<int32,string> V_1,
           class [mscorlib]System.Func`2<int32,string> V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
  // ...
  IL_000b:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                          class [mscorlib]System.Delegate)
  // ...
} // end of method Foo::add_OnCall

Aynı şekilde Delegate.Removekullanılır remove_OnCall.

Bir olay nasıl başlatılır?

Çağırmak OnCalliçin Do(), arg'yi yükledikten sonra son birleştirilmiş temsilciyi çağırır:

IL_0026:  callvirt   instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)

Bir abone bir etkinliğe tam olarak nasıl abone olur?

Ve son olarak, Mainşaşırtıcı bir şekilde, OnCallolaya abone olmak add_OnCall, Fooörnek üzerinde yöntem çağırarak yapılır .


3
Aferin!! Bu soruyu sormayalı çok uzun zaman oldu. İki parçalı sorumu doğrudan yanıtlayan kelimeyi en üste koyabilirseniz (yani, "1 numaralı yanıt hayırdır; # 2 yanıt hayırdır"), o zaman bunu resmi yanıt yapacağım. Gönderinizin orijinal sorularıma cevap verecek tüm parçalar olduğuna bahse girerim, ancak artık C # kullanmadığım için (ve diğer Google çalışanları bu kavramlar için yeni olabilir) bu yüzden cevapları açık hale getiren bir sözlü dil istiyorum.
Alexander Bird

Teşekkürler @AlexanderBird, cevapları en üste koymak için düzenledim.
KFL

@KFL, hala belirsiz, ben de Alex ile aynı yorumu bırakmak üzereydim. Basit bir "Evet, eşzamanlıdırlar" yararlı olabilir
Johnny 5

71

Bu genel bir cevaptır ve varsayılan davranışı yansıtır:

  1. Evet, olaya abone olan yöntemler zaman uyumsuz değilse, iş parçacığını engeller.
  2. Birbiri ardına idam edilirler. Bunun başka bir dönüşü vardır: Bir olay işleyicisi bir istisna atarsa, henüz yürütülmemiş olay işleyicileri çalıştırılmayacaktır.

Bununla birlikte, olayları sağlayan her sınıf, olayını eşzamansız olarak uygulamayı seçebilir. IDesign , EventsHelperbunu basitleştiren bir sınıf sağlar .

[Not] bu bağlantı, EventsHelper sınıfını indirmek için bir e-posta adresi sağlamanızı gerektirir. (Ben hiçbir şekilde bağlı değilim)


Uygun bir neden sunmamakla birlikte ikisinin ilk noktayla çeliştiği birkaç forum yazısı okudum. Cevabınızdan şüphem yok, (şimdiye kadar yaşadıklarımla eşleşiyor) ilk noktada herhangi bir resmi belge var mı? Bundan emin olmam gerekiyor, ancak bu konuda resmi bir şey bulmakta güçlük çekiyorum.
Adam LS

@ AdamL.S. Bu, olayın nasıl adlandırıldığı ile ilgilidir. Yani bu gerçekten olayı sağlayan sınıfa bağlıdır.
Daniel Hilgarth

14

Etkinliğe abone olan delegeler, eklendikleri sırayla eşzamanlı olarak çağrılır. Delegelerden birinin bir istisna atarsa, olanları aşağıdaki olmaz çağrılabilir.

Olaylar çok noktaya yayın delegeleri ile tanımlandığından, kendi ateşleme mekanizmanızı yazabilirsiniz.

Delegate.GetInvocationList();

ve temsilcileri eşzamansız olarak çağırmak;


12

Olaylar yalnızca temsilcilerden oluşan dizilerdir. Temsilci çağrısı eşzamanlı olduğu sürece, olaylar da eşzamanlıdır.



3

C # 'teki olaylar, ikinci bir iş parçacığını manuel olarak başlatmadığınız sürece eşzamanlı olarak çalışır (her iki durumda da).


Zaman uyumsuz bir olay işleyicisi kullanmama ne dersiniz? Daha sonra başka bir ileti dizisinde çalışacak mı? "Async all way" hakkında bir şeyler duydum, ancak async olay işleyicilerinin kendi iş parçacığı var gibi görünüyor? Anlamıyorum: / Lütfen beni aydınlatabilir misin?
Winger Sendon

3

Olaylar eşzamanlıdır. Olay yaşam döngüsünün olduğu gibi çalışmasının nedeni budur. Başlatma yüklemelerden önce gerçekleşir, yüklemeler işlemeden önce gerçekleşir vb.

Bir olay için hiçbir işleyici belirtilmezse, döngü sadece parlar. Birden fazla işleyici belirtilirse, sırayla çağrılırlar ve biri diğeri tamamen bitene kadar devam edemez.

Eşzamansız aramalar bile bir dereceye kadar eşzamanlıdır. Başlangıç ​​tamamlanmadan sonu çağırmak imkansızdı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.