上次讲了高效并行处理,在实际场景中,很多时候还需要轮询处理,比如消息队列,当处理完成队列中的所有消息后,等待一段时间后,需要再一次轮询该队列,这样可以实现不间断的数据处理,这样的场景,实际上是一个通用场景,因此,有必要设计一个轮询类来封装这个场景行为
PollingHelper类中的Polling方法就是用来处理这个场景的,
sourceGereratorFun参数,用来生成数据源,每次轮询的时候都会重新调用该参数,可以在这里重新查询数据源
maxDegree参数,设置并行度
interval参数,每次数据源处理完成后,到下一次轮询之间,需要等待的毫秒数,因为我们必须要有释放CPU时间的机制,不能一直占用,这是基本原则
body参数,不用多说,就是实际处理数据的行为,将自己的行为写在这里
exceptionHandler参数,在轮询处理的时候,针对异常的处理,通常情况下,我们不能中断整体轮询业务,因此,这里只是会去记录错误,比如记录进日志
返回结果为IAsyncPollingResult,调用方通过这个结果,调用方可以用来优雅的控制轮询的结束,而不是粗暴的直接中断,
这里要说一些关于DDD的设计,Polling属于DDD中的Service,那么它一定是无状态的,所以,我通过设计IAsyncPollingResult来将相关状态封装到这个返回对象中,那么Service本身就可以无状态了,在设计DDD的Service的时候,如果该Service对于调用方来说是必须有状态的(这里的Polling就是这个情况),我们都是通过这种方式来处理的,将有状态的结果的控制权交给调用方
对于开发人员来说,一定要善于使用行为封装,也就是Func、Action这些代理,当开发语言没有代理的情况下,只能通过接口来封装行为,稍显麻烦,尤其是内联参数的传递,C#有unc、Action,搭配lambda,很容易就实现了内联参数的传递(但也要非常注意作用域,否则很容易出现隐藏的引用错误)
回到主题,有了PollingHelper.Polling方法,轮询问题的主干业务也就迎刃而解了,而代码,相当少
这里的轮询方案,数据资源一定是互相独立的才可以这么做,因为实际处理是无序的,如果需要有序处理,则有其他的方式,以后会讲
Sample代码还是老地方