我需要制定一个可扩展的流程。该进程主要有 I/O 操作和一些次要的 CPU 操作(主要是反序列化字符串)。该流程在数据库中查询 url 列表,然后从这些 url 中获取数据,将下载的数据反序列化为对象,然后将部分数据保存到 crm 动态以及另一个数据库中。之后我需要更新第一个处理 url 的数据库。部分要求是使并行度可配置。
最初,我想通过一系列带有等待的任务来实现它,并使用信号量限制并行性 - 非常简单。然后我读了 @Stephen Cleary 的一些帖子和答案,其中建议使用 TPL Dataflow,我认为它可能是一个很好的候选者。然而,我想确保我通过使用数据流来“复杂化”代码是为了一个有价值的事业。我还得到了使用的建议ForEachAsync 扩展方法 https://blogs.msdn.microsoft.com/pfxteam/2012/03/05/implementing-a-simple-foreachasync-part-2/这也很容易使用,但是我不确定它是否会因为它对集合进行分区的方式而导致内存开销。
对于这种情况,TPL Dataflow 是一个不错的选择吗?它比 Semaphore 或 ForEachAsync 方法更好 - 如果我通过 TPL DataFlow 实现它而不是其他每个选项(Semaphore/ForEachASync),我实际上会获得什么好处?
该进程主要有IO操作和一些次要的CPU操作(主要是反序列化字符串)。
这几乎只是 I/O。除非那些字符串是huge,反序列化不值得并行化。您正在执行的 CPU 工作类型将被淹没在噪音中。
因此,您需要关注并发异步。
-
SemaphoreSlim
正如您所发现的,这是标准模式。
- TPL Dataflow 还可以实现并发(异步和并行形式)。
ForEachAsync
可以采取多种形式;请注意,在博客文章 https://blogs.msdn.microsoft.com/pfxteam/2012/03/05/implementing-a-simple-foreachasync-part-2/你提到的,有5该方法有不同的实现,每种实现都是有效的。 “迭代可能有许多不同的语义,每种语义都会导致不同的设计选择和实现。”出于您的目的(不希望 CPU 并行化),您不应该考虑使用Task.Run
或分区。在异步并发世界中,任何ForEachAsync
实现只是隐藏它实现的语义的语法糖,这就是我倾向于避免它的原因。
这给你留下了SemaphoreSlim
vs. ActionBlock
。我通常建议人们从SemaphoreSlim
首先,如果他们的需求变得更加复杂(他们似乎会从数据流管道中受益),请考虑转向 TPL 数据流。
例如,“部分要求是使并行度可配置。”
您可以从允许一定程度的并发开始 - 被限制的事物是单个整体操作(从 url 获取数据、将下载的数据反序列化为对象、持久保存到 crm 动态和另一个数据库中,以及更新第一个数据库)。这是哪里SemaphoreSlim
将是一个完美的解决方案。
但是您可能决定要拥有多个旋钮:例如,一个用于下载 URL 数量的并发度,一个用于持久化的单独并发度,以及一个用于更新原始数据库的单独并发度。然后,您还需要限制这些点之间的“队列”:内存中只有这么多反序列化对象等 - 以确保具有慢速数据库的快速 url 不会导致您的应用程序使用过多的问题记忆。如果这些是有用的语义,那么您已经开始从数据流的角度来处理问题,这就是您可能会更好地使用像 TPL Dataflow 这样的库的服务。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)