初探System.Threading.Channels
。
System.Threading.Channels
是.Net Core基础类库中实现的一个多线程相关的库,专门处理数据流相关的操作,用来在生产者和订阅者之间传递数据(不知道可不可以理解为线程间传递数据,我把它类比成了Go语言中的Channel),使用时需要通过NuGet安装。
这个库的前身是System.Threading.Tasks.Channels
,来自实验性质的核心类库项目https://github.com/dotnet/corefxlab,但是在2017年9月就不再更新了,目前使用的话需要用到最新的System.Threading.Channels
库,如果你也是第一次接触的话,就直接上手研究System.Threading.Channels
就可以了。
Channel
API操作基于Channel
对象,其操作主要由ChannelReader
和ChannelWriter
两部分组成,由Channel
t提供的工厂方法创建一个有容量限制(或者无限制、最大容量限制)的channel
。这点类似于Go语言中的chan
的容量,二者在这里有很多的类似的地方,也有不同的地方。
1.1. 和Go语言channel的一些比较
Go语言中的channel默认是没有容量的,在使用这个没有容量的channel时,生产者和消费者必须“流动”起来,否则将会阻塞,也就是当生产者写入channel一个数据时,必须同时有一个接收者接收,否则写入操作会停止,等待有一个消费者取走channel中的数据,写入操作才会继续。
在System.Threading.Channels
库中,没有类似Go语言的默认容量的机制,需要按需调用不同的Channel
对象:
public static Channel<T> CreateBounded<T>(int capacity);
:可以创建一个带有容量限制的Channel
实例对象。public static Channel<T> CreateBounded<T>(BoundedChannelOptions options)
:创建一个自定义配置的Channel
实例对象,可配置容量、以及在接收到新数据时的操作模式等等:BoundedChannelFullMode.Wait
:等待当前写入完成BoundedChannelFullMode.DropNewest
:删除并忽略管道中写入的最新的数据BoundedChannelFullMode.DropOldest
:删除并忽略管道中最旧的数据BoundedChannelFullMode.DropWrite
:删除当前正在写的数据,以写入管道中的新数据
public static Channel<T> CreateUnbounded<T>();
:创建一个没有容量限制的Channel
实例对象,在实际使用时应当谨慎使用该创建方式,因为可能会发生OutOfMemoryException
。public static Channel<T> CreateUnbounded<T>(UnboundedChannelOptions options)
:创建一个自定义配置的没有容量限制的Channel
实例对象。该配置选项因为没有容量限制所以不会有写入等待操作模式,只有默认的一些配置:public bool SingleWriter { get; set; }
:是否需要一个一个读public bool SingleReader { get; set; }
:是否需要一个一个写public bool AllowSynchronousContinuations { get; set; }
:是否需要异步连续操作(我个人理解为异步操作时同时进行读写)
Go语言的channel机制和System.Threading.Channels
的不同之处有两个:
Go语言没有无限容量的channel,而且就我个人的想法而言,无限容量并不“无限”,因为内存是有限的。
System.Threading.Channels
没有单向的channel类型。在Go中可以创建“只读”或者“只写”的channel,但是System.Threading.Channels
中没有提供这种操作。
1.2. 生产者、消费者需要的方法
生产者需要使用的一些方法:TryWrite
/WriteAsync
/WaitToWriteAsync
/Complete
消费者需要使用的一些方法:TryRead
/ReadAsync
/WaitToReadAsync
/Completion
方法介绍:
TryRead/TryWrite
:尝试使用同步方式读取或写入一项数据,返回读取或者写入是否成功。TryRead
同时会以out
的形式返回读取到的数据。ReadAsync/WriteAsync
:使用异步方式写入或者读取一项数据。TryComplete/Completion
:可以将channel标记为完成状态,这样就不会写入多余的错误数据,如果从已完成状态的channel中ReadAsync
时会抛出异常,所以在不需要异步读取时建议经常使用TryRead
。WaitToReadAsync/WaitToWriteAsync
:在尝试读取或者写入数据之前,调用该方法可获得一个Task<bool>
表示读取或者写入操作能否进行。
创建一个控制台程序演示channel的用法:
|
|
借助代码中的注释应当可以理解示例代码的作用,对其中的关键点做个说明:
写入器只有一个,写入的容量由channel的容量控制。
读取器可以设置多个,由
Task
调度同时读取。
2.1. 写入器、读取器无等待
写入器和读取器不等待,不停的读写数据,有一个读取器,总共写入50个数据,channel的容量为5,调用传参如下:
|
|
结果:
写入读取操作在一秒内完成了,观察输出可以发现,写入和读取交替进行,写入的数据会立刻被读取器读取出来打印在终端内。
2.2. 读取器阻塞(等待)
将读取器的等待时间设置长一些,观察一下写入器是否会被阻塞,调用传参如下:
|
|
结果:
从输出的结果可以看见,在程序开始时写入器写入了6个数据(但是调试的时候capacity的值时5,这里的机制有待考证),然后每过10秒读取器读取一个数据后,写入器才能写入一个数据,由于读取器的速度限制相当于将写入器也进行了阻塞。
2.3. 多个读取器同时读取
读取器还是每读取一次暂停10秒,但是有5个Task同时读取,调用传参如下:
|
|
结果:
从输出可以看出来,5个读取器Task可以每10秒钟同时读取5个数据,而写入器也同样的几乎是每次写入5个数据。
System.Threading.Channels
作为一个线程间通信的库,用来当作发布者/订阅者组件使用非常方便。但是比起Go语言中的channel还是有些区别的,因为c#的Async
/Await
从某中意义上讲,并不是真正的多线程。
|
|
结果:
https://medium.com/@alexyakunin/go-vs-c-part-1-goroutines-vs-async-await-ac909c651c11
https://github.com/dotnet/corefx/blob/master/src/System.Threading.Channels/tests/ChannelTests.cs
https://sachabarbs.wordpress.com/2018/11/28/system-threading-channels/
初探System.Threading.Channels相关推荐
- System.Timers.Timer与System.Threading.Timer
我最近一直在查看一些可能的计时器,而Threading.Timer和Timers.Timer对我来说是必要的(因为它们支持线程池). 我正在制作游戏,我计划使用不同类型的活动,间隔不同等. 哪个最好? ...
- System.Threading.Timer类的TimerCallback 委托
System.Threading.Timer类的TimerCallback 委托 Written by: Rickie Lee Nov. 19, 2004 System.Threading.Timer ...
- System.Threading.Interlocked.Exchange(ref m_Value, value);
System.Threading.Interlocked.Exchange(ref m_Value, value); 转载于:https://www.cnblogs.com/andy_tigger/a ...
- System.Threading.Timer使用心得
System.Threading.Timer使用心得 2008-11-20 00:09 System.Threading.Timer 是一个使用回调方法的计时器,而且由线程池线程服务,简单且对资源要求 ...
- C# 关闭进程的时候总是捕捉到System.Threading.ThreadAbortException: 正在中止线程
C# 关闭进程的时候总是捕捉到System.Threading.ThreadAbortException: 正在中止线程 这是由ThreadAbortException抛出的 可以写成下面的样子 tr ...
- System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)
System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1) 在vb里面 等价于i=i-1 在C#里面 等价于i-- 是有C#自 ...
- 转载 Net多线程编程—System.Threading.Tasks.Parallel
.Net多线程编程-System.Threading.Tasks.Parallel System.Threading.Tasks.Parallel类提供了Parallel.Invoke,Paralle ...
- NET 4.0 System.Threading.Tasks学习笔记
由于工作上的需要,学习使用了System.Threading.Tasks的使用,特此笔记下来. System.Threading.Tasks的作用: Tasks命名空间下的类试图使用任务的概念来解决线 ...
- System.Threading.Thread类方法
System.Threading.Thread类是创建并控制线程,设置其优先级并获取其状态最为常用的类.他有很多的方法,在这里我们将就比较常用和重要的方法做一下介绍: Thread.Start():启 ...
最新文章
- 【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )
- java逻辑移位和算术移位,关于对移位运算的理解
- 扎克伯格做了26张PPT
- “你的板子短路了,正在冒烟!”
- MySQL 多表查询、连接查询(内连接、外连接)
- 关于CleanMyMac常见问题与解答
- Odoo10教程---模块化二:模型间关系,继承,计算字段等
- Java基础学习总结(176)——JDK 16 正式发布,一次性发布 17 个新特性
- js中的substr和substring
- 软件缺陷分析方法:ODC
- oa项目经验描述_项目执行简历中的项目经验怎么写
- LeetCode-SQL(八)
- WEB渗透测试——信息收集
- 【理财入门二】复利思维
- AI周报丨标清变4k?B站超分辨率算法开源;强化学习算法控制核聚变登上《nature》
- 网页防封链接制作的原理有哪些?
- laravel连接mysql连接数过多_Laravel 使用Voyager导致多个数据库连接总是返回默认连接?...
- Face Paper:SeNet论文详解
- The Cook and the Chef: Musk’s Secret Sauce
- CJ20N/CN21/CN22/CN23 - 网络屏幕增强(SMOD: CNEX0016)
热门文章
- windows驱动程序编写_如何在Windows中回滚驱动程序
- raspberry pi_每日新闻摘要:新型iMac,NVIDIA的Raspberry Pi竞争对手等
- 搭建 vue2 单元测试环境(karma+mocha+webpack3)
- 自动为DEV GridView控件添加SizeChanged事件
- C++ float的内存布局
- 【CodeForces 577C】Vasya and Petya’s Game
- 稍微成型点的用WEBSOCKET实现的实时日志LOG输出
- Nginx+Tomcat动静态资源分离
- 【Android开发】Android应用程序目录结构
- RTC 媒体流数据包丢包问题解决