在.NET中使用TPL

时间:2016-05-11 14:55:55

标签: c# .net parallel-processing async-await task-parallel-library

我必须在我的一个应用程序中重构一个相当耗时的过程,并且经过一些研究后我认为它是使用TPL的完美匹配。我想澄清一下我对它的理解,并询问是否还有其他问题需要考虑。

简而言之,我有一个Windows服务,它在一夜之间运行,并向大约10000个用户发送带有数据更新的电子邮件。在场时,整个过程大约需要8小时才能完成。我想将它减少到最多2小时

应用程序工作流程如下:  1.遍历所有用户列表  2.检查是否必须通知该用户  3.如果是,请通过调用外部服务创建电子邮件正文  4.发送电子邮件

对代码的分析表明,步骤3是最耗时的,并且需要大约3,5秒才能完成。这意味着,当处理10000个用户时,我的应用程序总共等待超过6小时,以便来自外部服务的响应!我认为这是一个足以尝试引入一些异步和并行处理的原因。

所以,我的计划是使用Parallel类和ForEach方法在步骤1中迭代用户。我可以理解这应该将每个用户的处理分配到一个单独的线程中,使它们并行运行?流程完全相互独立,每个流程都不会返回任何值。在抛出任何异常的情况下,它将保留在日志db中。关于步骤3,我想将对外部服务的调用转换为异步调用。据我所知,这将释放线程上的资源,以便Parallel类可以重用它来开始处理列表中的下一个用户?

我阅读了有关TPL的MS文档,尤其是Potential Pitfalls in Data and Task Parallelism文档,我唯一不确定的是"避免写入共享内存位置"。我使用本地整数来计算处理的电子邮件总数。至于所有其他方面,我非常肯定他们不适用于我的方案。

我的问题是,目前还没有任何实施。我试图实现的是什么(尤其是异步等待外部服务调用的部分)?我应该知道可能影响我实施的任何其他障碍吗?有没有更好的方法来改善工作流程?

只是为了澄清我使用.Net v4.0

2 个答案:

答案 0 :(得分:4)

是的,您可以使用TPL解决您的问题。如果你不能影响你的外部问题,那么这可能是最好的方法。

但是,如果您可以让外部来源接受批次,则可以获得最大收益。因为这个源实际上可以优化性能。现在,您有一条消息开销,包含10000条消息,用于序列化,发送,处理,接收和反序列化。这是可以一次完成的事情。此外,如果他们知道他们将获得多条记录,您的外部资源可能能够优化他们所做的工作。

所以底线是:如果你需要在本地进行优化,那么TPL就可以了。如果您想优化整个流程以获得实际收益,请尝试查看您的外部资源是否可以为您提供帮助,因为这是您可以取得实际进展的地方。

答案 1 :(得分:1)

您没有显示任何代码,我假设第4步(发送电子邮件)也不是那么快。

对于所提出的案例,除非您从第3步开始的外部服务(通过调用外部服务创建电子邮件正文)并行处理请求并支持大量同时请求,否则您将无法获得多少收益用这个重构器。

换句话说,首先测试外部服务和电子邮件服务器:

  • 并行请求执行

    测试方法是至少发送2个请求,并观察处理它们需要多长时间。

    如果它需要大约一倍的时间,请求会有一些串行处理,要么排队,要么正在进行一些广泛的锁定。

  • 加载测试

    上升到4,8,12,16,20等,看看它开始降级的地方。

    您应该对同时请求的数量设置一个限制,以保持执行时间超过例如假设您是唯一的消费者

    ,处理单个请求所需时间的80%

    或者在开始降级之前的一些请求(例如除以消费者的数量)以使外部服务可供其他消费者使用。

只有这样你才能决定重构是否值得。如果您无法更改外部服务或电子邮件服务器,则必须对其进行加权,以提供足够的并行功能而不会降级。

即便如此,要切合实际。不要让您的服务将外部服务和电子邮件服务器推向生产中的极限。