我最近一直在熟悉.net Core中引入的新Channel<T>类型。我想在它第一次发布的时候我了解过它,但是有关文章非常非常少,我不能理解它们与其他队列有什么不同。

在使用了一段时间后,我终于看到了它们的吸引力和真正的力量。最值得注意的是大型异步后台操作,这些操作几乎需要双向通信来同步它们正在做的事情。这句话有点拗口,但希望在本系列文章结束时,你会清楚什么时候应该使用Channel<T>,什么时候应该使用一些更基本的东西,比如Queue<T>。

Channel是什么?

从核心来说,Channel本质上是.net中的一种新的集合类型,它与现有的Queue<T>类型非常相似,但有额外的好处。在真正尝试研究这个主题时,我发现的问题是,许多现有的外部队列技术(IBM MQ、Rabbit MQ等)都有“channel”的概念,它们的范围从完全抽象的思维过程,到系统中实际的物理类型。

现在也许我大错特错,但如果你认为.net中的Channel就好比是允许等待新消息的一个队列,并告诉生产者要保持队列越来越大,消费者无法跟上,我认为这很难出错。

这里我提到了一个关键词,生产者/消费者。你可能还听说过Pub/Sub。但它们是不可互换的。

Pub/Sub描述的是某人发布信息,一个或多个“订阅者”监听该信息并对其采取一定的响应行为。这里不存在负载平衡,因为当添加订阅服务器时,它们本质上与其他所有人获得相同消息的副本。

在图表形式中,Pub/Sub看起来有点像这样:

生产者/消费者描述生产者发布消息的行为,并且有一个或多个消费者可以对该消息进行操作,但是每个消息只读取一次。它不会分发到每个订阅者。

当然,用图表的形式:

另一种思考生产者/消费者的方式是想象你去超市结账。当顾客想结帐时,排队的队伍变长了,你可以简单地打开更多的收银台来处理这些顾客。这个小小的思考过程实际上是很重要的,因为如果你不能打开更多的收银台怎么办?排队的队伍应该越来越长吗?如果收银台操作员坐在那里,但没有顾客怎么办?他们是应该当天就打包回家呢,还是应该被告知坐着等客人来了再说。

这通常被称为生产者-消费者问题,这是Channel要解决的问题。

基础Channel示例

与Channel有关的所有东西都在System.Threading.Channels中。在以后的版本中,这似乎是与标准的.net Core项目捆绑在一起的,但如果不是,这里有一个nuget包:https://www.nuget.org/packages/System.Threading.Channels。

一个极其简单的Channel示例是这样的:

static async Task Main(string[] args)
{
var myChannel = Channel.CreateUnbounded(); for (int i = 0; i < 10; i++)
{
await myChannel.Writer.WriteAsync(i);
} while (true)
{
var item = await myChannel.Reader.ReadAsync();
Console.WriteLine(item);
}
}

这里没有太多可谈的。我们创建了一个“无限的”通道(这意味着它可以容纳无限项,但在本系列的后续内容中会有更多内容)。我们写10项,读10项,在这一点上,它与我们在.net中见过的任何其他队列没有太大区别。

Channel是线程安全的

没错,通道是线程安全的。这意味着多个线程可以读写同一个通道而不会出现问题。如果我们看一下这里的Channel源代码,我们可以看到它是线程安全的,因为它使用锁和内部“队列”的组合来同步读/写器,一个接一个地读/写。

实际上,Channel的预期用例是多线程场景。例如,如果我们使用上面的基本代码,当我们实际上不需要线程安全性时,维护线程安全性实际上会有一些开销。所以在那个例子中,我们可能只使用Queue<T>更好。但是这段代码呢?

static async Task Main(string[] args)
{
var myChannel = Channel.CreateUnbounded(); _ = Task.Factory.StartNew(async () =>
{
for (int i = 0; i < 10; i++)
{
await myChannel.Writer.WriteAsync(i);
await Task.Delay(1000);
}
}); while (true)
{
var item = await myChannel.Reader.ReadAsync();
Console.WriteLine(item);
}
}

在这里,我们有一个单独的线程写入消息,而我们的主线程读取消息。你会注意到有趣的事情是,我们添加了消息之间的延迟。怎么能调用ReadAsync()?没有TryDequeue或Dequeue,如果队列中没有消息,它就运行null,对吗?

答案是Channel Reader的“ReadAsync()”方法实际上会“等待”一个消息。因此,不需要在等待消息时执行一些荒谬的循环,也不需要在等待时完全阻塞线程。我们将在以后的文章中进一步讨论这个问题,但是你要知道你可以使用ReadAsync来等待新的消息,而不是编写一些自定义的代码来做同样的事情。

接下来是什么?

现在你已经掌握了基础知识,下一篇让我们看看使用Channel一些更高级的场景。

欢迎关注我的公众号,如果你有喜欢的外文技术文章,可以通过公众号留言推荐给我。

原文链接:https://dotnetcoretutorials.com/2020/11/24/using-channels-in-net-core-part-1-getting-started/

在.NET Core中使用Channel(一)的更多相关文章

  1. 在.NET Core中使用Channel(二)

    在我们之前的文章中,看了一些非常简单的例子来说明Channel是如何工作的,我们看到了一些非常漂亮的特性,但大多数情况下它与其他某某Queue实现非常相似.让我们进入一些更高级的话题.我说的是高级,但 ...

  2. 在.NET Core中使用Channel(三)

    到目前为止,我们一直在使用所谓的"Unbounded"通道.你会注意到,当我们创建通道时,我们这样做: var myChannel = Channel.CreateUnbounde ...

  3. ExpandoObject与DynamicObject的使用 RabbitMQ与.net core(一)安装 RabbitMQ与.net core(二)Producer与Exchange ASP.NET Core 2.1 : 十五.图解路由(2.1 or earler) .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

    ExpandoObject与DynamicObject的使用   using ImpromptuInterface; using System; using System.Dynamic; names ...

  4. .NET Core中使用RabbitMQ正确方式

    .NET Core中使用RabbitMQ正确方式 首先甩官网:http://www.rabbitmq.com/ 然后是.NET Client链接:http://www.rabbitmq.com/dot ...

  5. .Net Core中使用Grpc

    一.Grpc概述 gRPC 基于如下思想:定义一个服务, 指定其可以被远程调用的方法及其参数和返回类型.gRPC 默认使用protocol buffers作为接口定义语言,来描述服务接口和有效载荷消息 ...

  6. gRPC在 ASP.NET Core 中应用学习(二)

    前言: 上一篇文章中简单的对gRPC进行了简单了解,并实现了gRPC在ASP.NET Core中服务实现.客户端调用:那么本篇继续对gRPC的4中服务方法定义.其他使用注意点进一步了解学习 一.gRP ...

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

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

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

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

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

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

随机推荐

  1. PyQt(Python+Qt)学习随笔:QListWidget的sortingEnabled属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListWidget的sortingEnabled属性用于控制列表部件中的项是否可以排序,如果为T ...

  2. RedHat操作指令第4篇

    top(查看动态进程运行情况) top 是一个更加有用的命令,可以监视系统中不同的进程所使用的资源.它提供实时的系统状态信息. 显示进程的数据包括 PID.进程属主.优先级.%CPU.%memory等 ...

  3. node.js、yarn、npm到底是什么?

    最近在部署环境,在没有开发脚本的情况下,自己根据以往其他项目中的脚本去生搬硬套,发现很难对项目的配置成功.对配置不成功的情况进行判断,发现是对脚本不熟悉,不了解其原理,实现方式也不知道,所以抽时间去了 ...

  4. Android10_原理机制系列_Window介绍及WMS的启动过程

    简介 Window简介 Android中,Window是一个重要部分,用户看到的界面.触摸显示界面进行一系列操作都涉及到Window.但实际上,Window本身并不具备绘制功能. 该篇简单介绍下Win ...

  5. 百度网盘下载器:SpeedPan2.3.8

    SpeedPan是款百度网盘资源下载工具,下载速度还行(至少比百度网盘快太多了),支持登录百度账号,也支持免登录下载.官网免费版的取消分享了,我从油管上看到了这个软件,分享给大家. 天翼云:https ...

  6. Day4 【Scrum 冲刺博客】

    每日会议总结 昨天已完成的工作 方晓莹(PIPIYing) 完善人员管理页的未完成部分 方子茵(Laa-L):无 黄芯悦(Sheaxx) 开始投诉反馈页面的开发 舒雯钰(LittleTaro) 博客的 ...

  7. element ui中循环出来的表格勾选问题

    需求是这样的,一个房主屋里面有多个电表,每一个表是一个账户,一次只能给一个账户缴费,在点击go按钮进行缴费,这个时候判断是否跨表勾选,跨表格勾选则弹窗提示,反之符合需求,走缴费逻辑 上代码 <! ...

  8. When you received Ubuntu...

    翻译软件 Goldendict 安装命令: sudo apt install goldendict 在 dit -> Dictinoaries -> Websites 中添加有道的链接: ...

  9. 题解-SHOI2005 树的双中心

    SHOI2005 树的双中心 给树 \(T=(V,E)(|V|=n)\),树高为 \(h\),\(w_u(u\in V)\).求 \(x\in V,y\in V:\left(\sum_{u\in V} ...

  10. 移动端H5开发中的常见问题处理

    1.问题之合成海报: 功能技术:http://html2canvas.hertzen.com 问题描述:合成模糊.合成区域内容错位,合成不完整,合成边缘白条等. 解决方案:如有页面布局正常合成错位的, ...