с событий# синхронно?
есть две части этого вопроса:
тут повышение событие блокирует поток, или он начинает выполнение EventHandlers асинхронно, и поток продолжается в то же время?
Это отдельные обработчики событий (подписано на событие) запускаются синхронно один за другим, или они запускаются асинхронно без гарантии того, что другие не работают одновременно время?
7 ответов:
чтобы ответить на ваши вопросы:
- создание события блокирует поток, если все обработчики событий реализованы синхронно.
- обработчики событий выполняются последовательно, один за другим, в том порядке, в котором они подписаны на событие.
мне тоже было любопытно о внутреннем механизме
eventи связанные с ними операции. Поэтому я написал простую программу и использоватьildasmчтобы покопаться в его реализации.короткий ответ:
- нет никакой асинхронной операции, связанной с подпиской или вызовом событий.
- событие реализуется с помощью резервного поля делегата того же типа делегата
- подписка осуществляется с
Delegate.Combine()- отписка производится с помощью
Delegate.Remove()- вызов выполняется путем простого вызова окончательного комбинированного делегат
вот что я сделал. Программа, которую я использовал:
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(); } }вот реализация Foo:
обратите внимание, что есть поле
OnCallи событиеOnCall. ПолеOnCallэто, очевидно, свойство поддержки. И это простоFunc<int, string>, ничего особенного здесь.теперь интересные части являются:
add_OnCall(Func<int, string>)remove_OnCall(Func<int, string>)- и как
OnCallвызывается вDo()как осуществляется подписка и отмена подписки?
вот сокращенно
add_OnCallреализация в CIL. Самое интересное, что он используетDelegate.Combineобъединить двух делегатов..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кроме того,
Delegate.Removeиспользуетсяremove_OnCall.как это событие вызывали?
для вызова
OnCallнаDo(), он просто вызывает окончательный объединенный делегат после загрузки arg:IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)как именно подписчик подписывается на событие?
и, наконец, в
Main, не удивительно, подписавшись наOnCallсобытие выполняется путем вызоваadd_OnCallметодFooэкземпляра.
Это общий ответ и отражает поведение по умолчанию:
- Да, он блокирует поток, если методы подписки на событие не асинхронный.
- они выполняются один за другим. Это имеет еще один поворот: если один обработчик событий создает исключение, обработчики событий, которые еще не выполнены, не будут выполнены.
сказав, что каждый класс, который предоставляет события может реализовать свое событие асинхронно. IDesign предоставляет класс под названием
EventsHelperэто упрощает дело.[Примечание] по этой ссылке необходимо указать адрес электронной почты для загрузки класса EventsHelper. (Я никоим образом не связан)
делегаты, подписанные на событие, вызываются синхронно в том порядке, в котором они были добавлены. Если один из делегатов создает исключение, следующие не будет называться.
поскольку события определяются с помощью делегатов многоадресной рассылки, вы можете написать свой собственный механизм запуска с помощью
Delegate.GetInvocationList();и вызов делегата асинхронно;
В общем, события синхронно. Однако есть некоторые исключения, такие как
System.Timers.Timer.Elapsedсобытие наThreadPoolthread ifSyncronisingObjectимеет значение null.Docs:http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
события одновременны. Вот почему жизненный цикл события работает именно так. Inits происходит до нагрузок, нагрузки происходят до рендеринга и т. д.
Если для события не указан обработчик, цикл просто проносится. Если указано более одного обработчика, они будут вызваны по порядку, и один не может продолжаться до тех пор, пока другой не будет полностью завершен.
даже асинхронные вызовы синхронны до некоторой степени. Было бы невозможно назвать конец до начала есть завершенный.
