这篇文章主要介绍了聊一聊C# 8.0中的await foreach使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
AsyncStreamsInCShaper8.0
很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样.
为什么写这篇文章
Async Streams这个功能已经发布很久了,在去年的Build 2018 The future of C#就有演示,最近VS 2019发布,在该版本的Release Notes中,我再次看到了这个新特性,因为对异步编程不太熟悉,所以借着这个机会,学习新特性的同时,把异步编程重温一遍.
本文内容,参考了Bassam Alugili在InfoQ中发表的Async Streams in C# 8,撰写本博客前我已联系上该作者并得到他支持.
Async / Await
C# 5 引入了 Async/Await,用以提高用户界面响应能力和对 Web 资源的访问能力。换句话说,异步方法用于执行不阻塞线程并返回一个标量结果的异步操作。
微软多次尝试简化异步操作,因为 Async/Await 模式易于理解,所以在开发人员当中获得了良好的认可。
详见The Task asynchronous programming model in C#
常规示例
要了解问什么需要Async Streams,我们先来看看这样的一个示例,求出5以内的整数的和.
static int SumFromOneToCount(int count)
{
ConsoleExt.WriteLine("SumFromOneToCount called!");
var sum = 0;
for (var i = 0; i <= count; i++)
{
sum = sum + i;
}
return sum;
}
调用方法.
static void Main(string[] args)
{
const int count = 5;
ConsoleExt.WriteLine($"Starting the application with count: {count}!");
ConsoleExt.WriteLine("Classic sum starting.");
ConsoleExt.WriteLine($"Classic sum result: {SumFromOneToCount(count)}");
ConsoleExt.WriteLine("Classic sum completed.");
ConsoleExt.WriteLine("################################################");
}
输出结果.
Yield Return
接下来,我们使用yield运算符使得这个方法编程延迟加载,如下所示.
static IEnumerable<int> SumFromOneToCountYield(int count)
{
ConsoleExt.WriteLine("SumFromOneToCountYield called!");
var sum = 0;
for (var i = 0; i <= count; i++)
{
sum = sum + i;
yield return sum;
}
}
主函数
static void Main(string[] args)
{
const int count = 5;
ConsoleExt.WriteLine("Sum with yield starting.");
foreach (var i in SumFromOneToCountYield(count))
{
ConsoleExt.WriteLine($"Yield sum: {i}");
}
ConsoleExt.WriteLine("Sum with yield completed.");
ConsoleExt.WriteLine("################################################");
ConsoleExt.WriteLine(Environment.NewLine);
}
运行结果如下.
Async Return
我们试着将async用于SumFromOneToCount方法(没有yield关键字).
static async Task<int> SumFromOneToCountAsync(int count)
{
ConsoleExt.WriteLine("SumFromOneToCountAsync called!");
var result = await Task.Run(() =>
{
var sum = 0;
for (var i = 0; i <= count; i++)
{
sum = sum + i;
}
return sum;
});
return result;
}
主函数.
static async Task Main(string[] args)
{
const int count = 5;
ConsoleExt.WriteLine("async example starting.");
// Sum runs asynchronously! Not enough. We need sum to be async with lazy behavior.
var result = await SumFromOneToCountAsync(count);
ConsoleExt.WriteLine("async Result: " + result);
ConsoleExt.WriteLine("async completed.");
ConsoleExt.WriteLine("################################################");
ConsoleExt.WriteLine(Environment.NewLine);
}
运行结果.
Task<IEnumerable>
我们根据假设把代码改造一遍,使用Task<IEnumerable<T>>来进行计算.
IAsyncEnumerable
其实,在C# 8.0中Task<IEnumerable>这种组合称为IAsyncEnumerable。这个新功能为我们提供了一种很好的技术来解决拉异步延迟加载的问题,例如从网站下载数据或从文件或数据库中读取记录,与 IEnumerable 和 IEnumerator 类似,Async Streams 提供了两个新接口 IAsyncEnumerable 和 IAsyncEnumerator,定义如下:
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
Task<bool> MoveNextAsync();
T Current { get; }
}
// Async Streams Feature 可以被异步销毁
public interface IAsyncDisposable
{
Task DiskposeAsync();
}
AsyncStream
下面,我们就来见识一下AsyncStrema的威力,我们使用IAsyncEnumerable来对函数进行改造,如下.
static async Task ConsumeAsyncSumSeqeunc(IAsyncEnumerable<int> sequence)
{
ConsoleExt.WriteLineAsync("ConsumeAsyncSumSeqeunc Called");
await foreach (var value in sequence)
{
ConsoleExt.WriteLineAsync($"Consuming the value: {value}");
// simulate some delay!
await Task.Delay(TimeSpan.FromSeconds(1));
};
}
private static async IAsyncEnumerable<int> ProduceAsyncSumSeqeunc(int count)
{
ConsoleExt.WriteLineAsync("ProduceAsyncSumSeqeunc Called");
var sum = 0;
for (var i = 0; i <= count; i++)
{
sum = sum + i;
// simulate some delay!
await Task.Delay(TimeSpan.FromSeconds(0.5));
yield return sum;
}
}
主函数.
static async Task Main(string[] args)
{
const int count = 5;
ConsoleExt.WriteLine("Starting Async Streams Demo!");
// Start a new task. Used to produce async sequence of data!
IAsyncEnumerable<int> pullBasedAsyncSequence = ProduceAsyncSumSeqeunc(count);
// Start another task; Used to consume the async data sequence!
var consumingTask = Task.Run(() => ConsumeAsyncSumSeqeunc(pullBasedAsyncSequence));
await Task.Delay(TimeSpan.FromSeconds(3));
ConsoleExt.WriteLineAsync("X#X#X#X#X#X#X#X#X#X# Doing some other work X#X#X#X#X#X#X#X#X#X#");
// Just for demo! Wait until the task is finished!
await consumingTask;
ConsoleExt.WriteLineAsync("Async Streams Demo Done!");
}
如果一切顺利,那么就能看到这样的运行结果了.
Client/Server的异步拉取
如果还没有理解Async Streams的好处,那么我借助客户端 / 服务器端架构是演示这一功能优势的绝佳方法。
同步调用
客户端向服务器端发送请求,客户端必须等待(客户端被阻塞),直到服务器端做出响应.
Tips
如果你使用的是.net core 2.2及以下版本,会遇到这样的报错.
总结
我们已经讨论过 Async Streams,它是一种出色的异步拉取技术,可用于进行生成多个值的异步计算。
Async Streams 背后的编程概念是异步拉取模型。我们请求获取序列的下一个元素,并最终得到答复。Async Streams 提供了一种处理异步数据源的绝佳方法,希望对大家能够有所帮助。
文章中涉及的所有代码已保存在我的GitHub中,请尽情享用!
https://github.com/liuzhenyulive/AsyncStreamsInCShaper8.0
致谢
之前一直感觉国外的大师级开发者遥不可及甚至高高在上,在遇到Bassam Alugili之后,我才真正感受到技术交流没有高低贵贱,正如他对我说的 The most important thing in this world is sharing the knowledge!
Thank you,I will keep going!!
参考文献: Async Streams in C# 8
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程学习网。
本文标题为:聊一聊C# 8.0中的await foreach使用
![](/xwassets/images/pre.png)
![](/xwassets/images/next.png)
- C# 使用Aspose.Cells 导出Excel的步骤及问题记录 2023-05-16
- WPF使用DrawingContext实现绘制刻度条 2023-07-04
- .NET CORE DI 依赖注入 2023-09-27
- Oracle中for循环的使用方法 2023-07-04
- 在C# 8中如何使用默认接口方法详解 2023-03-29
- Unity3D实现渐变颜色效果 2023-01-16
- c# 模拟线性回归的示例 2023-03-14
- user32.dll 函数说明小结 2022-12-26
- Unity Shader实现模糊效果 2023-04-27
- 如何使用C# 捕获进程输出 2023-03-10