C#学习:异步函数_异步流

2022/6/29 14:23:13

本文主要是介绍C#学习:异步函数_异步流,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

在C#8之前,可以使用yield return实现迭代器,也可以用await书写异步函数。但无法两者结合,实现一个可以等待的迭代器。C#8引入了异步流解决了这个问题。

异步流基于以下两个接口。

public interface IAsyncEnumerable<out T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator(...);
}
public interface IAsyncEnumerator<out T>
    : IAsyncDisposable
{
    T Current { get; }
    ValueTask<bool> MoveNextAsync();
}

ValueTask<T>结构体封装了Task<T>,其行为和Task<T>相似。在任务对象同步完成的情况下具有更好的执行性能。

结合使用迭代器和异步方法的规则来书写方法就可以创建一个异步流。即该方法应同时具备yield returnawait,并且返回值为IAsyncEnumerable<T>

async IAsyncEnumerable<int> RangeAsync (
	int start, int count, int delay)
{
	for (int i = start; i < start + count; i++)
	{
		await Task.Delay (delay);
		yield return i;
	}
}

相应地,使用await foreach语句就可以消费异步流:

await foreach (var number in RangeAsync (0, 10, 500))
{
	Console.WriteLine (number);
}

以上例子,数据持续以每0.5秒一个的速度到达。
而如果项以下例子中使用Task<IEnumerable<T>>,则只有所有数据都准备好时才会最终返回:

static async Task<IEnumerable<int>> RangeTaskAsync(int start, int count, int delay)
{
	List<int> data = new List<int>();
	for (int i = start; i < start + count; i++)
	{
		await Task.Delay (delay);
		data.Add (i);
	}
	return data;
}

消费上例中的结果只需使用foreach语句即可:

foreach (var data in await RangeTaskAsync(0, 10, 500))
{
	Console.WriteLine (data);
}
查询IAsyncEnumerable<T>

System.Linq.Async Nuget包包含了对IAsyncEnumerable<T>查询的LINQ查询运算符。这样就可以像查询IEnumerable<T>那样书写查询了。
例如,可以对前面RangeAsync方法书写LINQ查询:

IAsyncEnumerable<int> query =
	from i in RangeAsync (0, 10, 500)
	where i % 2 == 0
	select i * 10; 

await foreach (var number in query)
{
	Console.WriteLine (number);
}
ASP.NET Core中的IAsyncEnumerable<T>

ASP.NET Core控制器的方法目前支持返回IAsyncEnumerable<T>对象了,此类方法必须标记async

[HttpGet]
public async IAsyncEnumerable<string> Get()
{
    using var dbContext = new DbContext();
    await foreach (var title in dbContext.Books
        .Select(b=>b.Title).AsAsyncEnumerable())
    {
        yield return title;
    }
}


这篇关于C#学习:异步函数_异步流的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程