博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
事件驱动之异步事件
阅读量:6319 次
发布时间:2019-06-22

本文共 3160 字,大约阅读时间需要 10 分钟。

前言

上一篇讲了事件,以及为什么要使用事件,主要是为了解耦,但是有同学就问了,同步如果订阅事件的人太多,比如13亿人都关心上头条的事,那么RaiseEvent得等13亿人都处理完,那得多久呀,从此再也不敢发事件了。 举个例子,你在网上下单,下完单要通知库房,甚至要通知供应商补货,如果都是同步的话,消费者还不等急死呀,实际上你在电商网站上下个单, 一般你很快就能到订单页面,那个页面告诉你:“兄弟,订单已经创建成功,订单号是xxxxx-xxxxx-xxxx-xxxx,你的订单已经提交到库房” 等。然后你就很快了的下另一单了。好吧, 提问的同学,说好的妹子呢?

实现思路

发出事件

public void Head() { var NewsPaper = new NewsPaper("南都娱乐"); NewsPaper.WriteToHeader("汪峰"); RaiseEvent(new HeadedEvent {Name = "汪峰"}); } private void RaiseEvent(HeadedEvent headedEvent) { EventBus.Publish
(new HeadedEvent { Name = "汪峰" }); }

所以我们只需在代码里RaiseEvent就可以了。

订阅事件

其实很简单,因为我们要实现的是同步的事件,我们只需要找到所有处理这个事件的实现类,然后调用所有就可以了。

public interface IEventHandler
where TEvent : Event{ void Handle(TEvent e); } public class HeadedEvent:Event { public string Name { get; set; } } public class GuoJiZhangMotherEventHandler : IEventHandler
{ public void Handle(HeadedEvent e) { Console.WriteLine(e.Name+", Are you kidding me?"); } } public class PiMingEventHandler:IEventHandler
{ public void Handle(HeadedEvent e) { Console.WriteLine(e.Name+", Guo Ji Zhang is your last wife?"); } }

我们可以看到正真的事件协调者是EventBus, 之前的代码如下是同步的。

public class EventBus{    public static void Publish
(T concreteEvent) where T: Event { var handlers = _container.ResolveAll
>(); foreach (var handle in handlers) { handle.Handle(concreteEvent); } } }

为了提高性能,我们可以先来第一步改进

public void Publish
(T @event) where T : Event { var handlers = _eventHandlerFactory.GetHandlers
(); handlers.AsParallel().ForAll((h)=> h.Handle(@event)); }

我们可以看到,现在并行处理可以大大加快速度,但是有两个问题,第一个问题就是没有处理异常,所以让我们加上异常。

public void Publish
(T @event) where T : Event { var handlers = _eventHandlerFactory.GetHandlers
(); handlers.AsParallel().ForAll((h)=> HandleEvent
(h,@event)); } private void HandleEvent
(IEventHandler
handle, T @event) where T : Event { try { handle.Handle(@event); } catch (Exception e) { // Log the exception, as the caller don't care this } } }

第二个问题,就是我们虽然用了并行加快了速度,但是还没有正真实现异步,整个程序还是等所有Handler处理完才返回。

public void Publish
(T @event) where T : Event { var handlers = _eventHandlerFactory.GetHandlers
(); handlers.Select(h => Task.Factory.StartNew(() => HandleEvent
(h, @event))); }

这段代码执行完,尽然发现Handler没有执行,好吧,原因是IQueryable的延迟执行,所以我们需要调用一下ToList

public void Publish
(T @event) where T : Event { var handlers = _eventHandlerFactory.GetHandlers
(); handlers.Select(h => Task.Factory.StartNew(() => HandleEvent
(h, @event))).ToArray(); }

好了,我们就这样轻易的实现了一个AsyncEventBus, 是不是感谢.Net的强大?

总结

这里还只是一个系统内部的Async, 如果涉及到系统之间的交互,这个就不行了,而且如果异步处理有错误,我们就会有信息丢失,所以需要更健壮的异步事件处理系统,这个后面再讲,但是一般的系统我们只需要把出错的时间记录下来,然后再看要不要处理就可以。

另外,异步要处理的东西很多,比如处理完毕后,如何通知用户,还是让用户刷新? 我个人建议,一般情况下都不要用异步,只有在真的需要的时候再用。

 

  • 作者: 王德水
  • 出处:
分类: ,
 
 
本文转自左正博客园博客,原文链接: ,如需转载请自行联系原作者
你可能感兴趣的文章
AspNetPager控件的最基本用法
查看>>
sessionKey
查看>>
高性能Javascript--脚本的无阻塞加载策略
查看>>
Java 编程的动态性, 第4部分: 用 Javassist 进行类转换--转载
查看>>
完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三
查看>>
iOS8 Push Notifications
查看>>
各大名企笔试及面经大全(程序猿必读)
查看>>
Oracle 连接、会话数的查看,修改
查看>>
Oracle 11g password过期被锁定报道 ORA-28000 the account is locked
查看>>
轨磁条简介
查看>>
NSQ部署
查看>>
大厂前端高频面试问题与答案精选
查看>>
如何设计高扩展的在线网页制作平台
查看>>
Git 2.5增加了工作树、改进了三角工作流、性能等诸多方面
查看>>
深度揭秘腾讯云低功耗广域物联网LPWAN 技术及应用
查看>>
与Jeff Sutherland谈敏捷领导力
查看>>
More than React(四)HTML也可以静态编译?
查看>>
React Native最佳学习模版- F8 App开源了
查看>>
云服务正在吞噬世界!
查看>>
Web语义化标准解读
查看>>