一、引言

上一篇博客 分享了使用 Channel 来实现针对大量数据的多线程异步处理,感谢大哥们在评论中提出的宝贵的问题和建议!本篇将分享使用 ActionBlock 如何实现,欢迎在评论区留言讨论。

二、ActionBlock介绍

什么是 ActionBlock?

ActionBlock是 .NET 中 TPL Dataflow 库的一部分,用于处理数据流和并行任务。它提供了一种简单而强大的方式来处理并行任务,并且可以轻松地实现生产者-消费者模式。

ActionBlock 的特点

  • 并行处理:ActionBlock可以配置为并行处理多个任务,从而提高处理效率
  • 异步编程:支持异步编程模型,可以避免阻塞线程,提高应用程序的响应速度和吞吐量
  • 数据流控制:可以通过设置最大并行度和其他选项来控制数据流的处理方式
  • 任务调度:可以用于调度和管理并行任务,确保任务按预期执行

ActionBlock 的使用场景

  • 生产者-消费者模式:可以用于实现生产者-消费者模式,其中生产者将数据发送到ActionBlock,消费者从ActionBlock中读取数据并进行处理
  • 数据流处理:适用于需要处理大量数据并且需要并行处理的场景,例如日志处理、数据转换等
  • 任务调度:可以用于调度和管理并行任务,确保任务按预期执行

ActionBlock 的基本用法

使用ActionBlock非常简单,主要步骤如下:

  1. 创建 ActionBlock:定义一个 ActionBlock,指定要执行的操作和并行选项
  2. 发送数据到 ActionBlock:使用SendAsync方法将数据发送到 ActionBlock
  3. 完成 ActionBlock:在所有数据发送完成后,调用Complete方法通知 ActionBlock 不再接收新的数据
  4. 等待处理完成:使用Completion属性等待所有数据处理完成

以下是一个简单的示例代码,展示了如何使用 ActionBlock:

using System.Threading.Tasks.Dataflow;

var actionBlock = new ActionBlock<int>(async item =>
{
// 模拟异步处理
await Task.Delay(100);
Console.WriteLine($"Processed item: {item}");
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 4 // 设置最大并行度
}); // 发送数据到 ActionBlock
for (int i = 0; i < 10; i++)
{
await actionBlock.SendAsync(i);
} // 完成 ActionBlock
actionBlock.Complete();
// 等待处理完成
await actionBlock.Completion; Console.WriteLine("All items processed.");

三、假设场景

假设我们有一组数据需要经过两个步骤的处理。每个数据项都需要进行初步处理,然后进行进一步处理。希望步骤2可以在步骤1产生结果数据后立即开始处理,而不是等待步骤1完全处理完毕。

四、解决方案

使用TransformBlockActionBlock来实现生产者-消费者模式。生产者负责读取数据并将其发送到TransformBlock中,消费者从TransformBlock中读取数据并进行处理。

以下是一个简单的示例代码,演示如何使用TransformBlockActionBlock实现生产者-消费者模式来处理数据:

using System.Threading.Tasks.Dataflow;

var cts = new CancellationTokenSource();
// 假设有一组数据
var dataItems = Enumerable.Range(0, 1000).Select(x => $"data_{x}").ToList(); var processor = new DataProcessor(10, cts.Token);
await processor.ProcessAsync(dataItems); Console.ReadKey(); /// <summary>
/// 数据处理器
/// </summary>
public class DataProcessor(int maxDegreeOfParallelism, CancellationToken cancellationToken)
{
public async Task ProcessAsync(List<string> dataItems)
{
// 创建一个 TransformBlock 用于步骤1的处理,并将结果发送到步骤2的 ActionBlock
var step1Block = new TransformBlock<string, string>(async dataItem => await Step1(dataItem), new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism,
CancellationToken = cancellationToken
}); // 创建一个 ActionBlock 用于步骤2的处理
var step2Block = new ActionBlock<string>(async dataItem =>
{
await Step2(dataItem);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism,
CancellationToken = cancellationToken
}); // 将 TransformBlock 链接到 ActionBlock
step1Block.LinkTo(step2Block, new DataflowLinkOptions { PropagateCompletion = true }); // 启动多个步骤1的任务(生产者)
foreach (var dataItem in dataItems)
{
await step1Block.SendAsync(dataItem, cancellationToken);
} // 完成步骤1的 TransformBlock 的写入
step1Block.Complete();
// 等待步骤1的 TransformBlock 处理完成
await step1Block.Completion; // 完成步骤2的 ActionBlock 的写入
step2Block.Complete();
// 等待步骤2的 ActionBlock 处理完成
await step2Block.Completion;
} private async Task<string> Step1(string dataItem)
{
// 模拟步骤1的处理(如初步处理数据)
await Task.Delay(10, cancellationToken);
Console.WriteLine($"Step1 processed data item: {dataItem}");
return dataItem;
} private async Task Step2(string dataItem)
{
// 模拟步骤2的处理(如进一步处理数据)
await Task.Delay(10, cancellationToken);
Console.WriteLine($"Step2 processed data item: {dataItem}");
}
}

代码解释:

  1. 创建Step1的 TransformBlock:在ProcessAsync方法中,我们首先创建了一个 TransformBlock,用于Step1的处理,TransformBlock 接受一个输入数据项,进行处理后返回一个输出数据项,TransformBlock<string, string>表示输入和输出都是string类型
  2. 创建Step2的 ActionBlock:创建一个 ActionBlock 用于Step2的处理,ActionBlock 接受一个输入数据项并进行处理,但不返回输出数据项。ActionBlock<string>表示输入是string类型
  3. 链接 TransformBlock 和 ActionBlock:将 TransformBlock 链接到 ActionBlock ,以便将Step1的处理结果发送到Step2进行处理,使用LinkTo方法将两个块连接起来,并设置PropagateCompletion为 true,表示当 TransformBlock 完成时,ActionBlock 也会完成
  4. 启动Step1的任务:逐个将数据项发送到 TransformBlock,并等待所有数据处理完成,使用SendAsync方法将数据项发送到 TransformBlock
  5. 等待任务完成:使用Complete方法通知 TransformBlock 不再接收新的数据,并使用Completion属性等待所有数据处理完成。然后完成Step2的 ActionBlock 的写入,并等待Step2的 ActionBlock 处理完成

在 .NET Core 中使用 ActionBlock 实现高效率的多步骤数据处理的更多相关文章

  1. 在ef core中使用postgres数据库的全文检索功能实战之中文支持

    前言 有关通用的postgres数据库全文检索在ef core中的使用方法,参见我的上一篇文章. 本文实践了zhparser中文插件进行全文检索. 准备工作 安装插件,最方便的方法是直接使用安装好插件 ...

  2. .NET Core 中的日志与分布式链路追踪

    目录 .NET Core 中的日志与分布式链路追踪 .NET Core 中的日志 控制台输出 非侵入式日志 Microsoft.Extensions.Logging ILoggerFactory IL ...

  3. .net core中Grpc使用报错:The remote certificate is invalid according to the validation procedure.

    因为Grpc采用HTTP/2作为通信协议,默认采用LTS/SSL加密方式传输,比如使用.net core启动一个服务端(被调用方)时: public static IHostBuilder Creat ...

  4. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  5. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  6. Asp.net Core中使用Session

    前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...

  7. 在ASP.NET Core中使用百度在线编辑器UEditor

    在ASP.NET Core中使用百度在线编辑器UEditor 0x00 起因 最近需要一个在线编辑器,之前听人说过百度的UEditor不错,去官网下了一个.不过服务端只有ASP.NET版的,如果是为了 ...

  8. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  9. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  10. ASP.NET Core中的依赖注入(3): 服务的注册与提供

    在采用了依赖注入的应用中,我们总是直接利用DI容器直接获取所需的服务实例,换句话说,DI容器起到了一个服务提供者的角色,它能够根据我们提供的服务描述信息提供一个可用的服务对象.ASP.NET Core ...

随机推荐

  1. python中的时间处理

    python程序编写中的时间处理涉及三种: 1.时间的显示: 2.时间的转换: 3.时间的运算. 时间处理模块:time模块 时间的三种表示方式: ①时间戳,从1970年1月1日开始,每过1s增加1, ...

  2. 【ZROJ2730】简单题 可持久化分块题解

    Description 给定一棵 \(n\) 个节点的树,每次询问编号为 \([l, r]\) 的点中有多少个是祖先关系. \(n, q \le 10^5\). Solution 直接做的话树上的祖先 ...

  3. 如何在Windows 11系统中将任意文件(如bat/log等)固定在开始菜单?

    在Windows 11系统中,默认只支持将.exe/文件夹/.zip固定在开始菜单,如果想将其他文件如.bat/.log等文件固定在开始菜单将在右键菜单中找不到选项. 一个更简单的办法: 对任意文件右 ...

  4. 云原生周刊:2024 年 K8s 基准报告 | 2024.4.8

    开源项目推荐 Argo CD Image Updater Argo CD Image Updater 是一个自动更新 Argo CD 管理的 Kubernetes 工作负载容器镜像的工具.简而言之,它 ...

  5. 云原生爱好者周刊:目前 WebAssembly 的最佳应用场景有哪些?

    云原生一周动态要闻: Istio 1.11 发布 Facebook.Google.Isovalent.微软和 Netflix 宣布成立 eBPF 基金会 GitHub 工程团队将开发环境迁移到 Cod ...

  6. Seralizable

    class CSer { private String name; private int age; public CSer() { } public CSer(String name, int ag ...

  7. mysql替换内容

    UPDATE storage SET guige = REPLACE(guige, '×', 'x')

  8. IDEA 2024.2.2 最新安装教程(附激活-2099年~)

    访问 IDEA 官网 下载 IDEA 2024.2.2 版本的安装包. 下载补丁https://pan.quark.cn/s/fcc23ab8cadf 检查 进入 IDEA 中后,点击菜单 Help ...

  9. 2个月搞定计算机二级C语言——真题(10)解析

    1. 前言 本篇我们讲解2个月搞定计算机二级C语言--真题10 2. 程序填空题 2.1 题目要求 2.2 提供的代码 #include <stdio.h> #pragma warning ...

  10. java中bimface 在线申请token。模型视角 模型批注处理

    在线申请token 1.首先引入包 <dependency> <groupId>com.bimface</groupId> <artifactId>bi ...