IAsyncEnumerable或IAsyncEnumerator的工厂 [英] Factory for IAsyncEnumerable or IAsyncEnumerator
问题描述
我想知道是否有一种方法可以通过Source对象(类似于 TaskCompletionSource
允许您执行某项任务.特别是, TaskCompletionSource
可以像其他任何参数一样传递.
也许是这样的:
公共类AsyncEnumerables {公共任务HandlerTask {放;}公共异步Task< string>ParentMethod(){var source = new AsyncEnumerableSource< int>();IAsyncEnumerable asyncEnumerable = source.GetAsyncEnumerable();HandlerTask = Task.Run(()=> handleAsyncResultsAs他们发生(asyncEnumerable));int n =等待someOtherTask();source.YieldReturn(n);var r = await ChildMethod(source);source.Complete();//此调用将导致HandlerTask完成.返回r;}私有异步Task< string>ChildMethod(AsyncEnumerableSource< int>源){source.YieldReturn(5);等待SomeOtherCall();source.YieldReturn(10);返回你好";}}
使用上述代码, handleAsyncResultsAs他们发生
任务将看到传递给YieldReturn的任何值.因此,它将看到以上代码中的 n
以及 ChildMethod
中的 5
和 10
.
如果您可以构建代码以利用 yield return
和 await foreach
的优势,那么情况会好得多.代码>.例如,这段代码几乎可以做同样的事情:
公共异步任务Consume(){var source = ParentMethod();HandlerTask = Task.Run(async()=> {等待foreach(源代码中的var项目){Console.WriteLine(item);}});}公共异步IAsyncEnumerable< int>ParentMethod(){等待Task.Yield();收益率13;等待foreach(ChildMethod()中的var项)退货项目;}私有异步IAsyncEnumerable< int>ChildMethod(){收益率5;等待Task.Yield();收益率10;}
但是,如果您确实需要异步可枚举来源",则需要首先识别一件事. TaskCompletionSource< T>
保存结果,即 T
(或例外).它充当容器.可以在等待任务之前设置结果.异步可枚举来源"是一回事-您需要它能够保留结果,然后再从中获取任何项目.异步可枚举来源"将需要保存多个结果-在这种情况下,是一个 collection .
实际上,您实际上要问的是可以作为异步枚举使用的集合".这里有几种可能,但我推荐的是一种 Channel :
公共异步任务< string>ParentMethod(){var source = Channel.CreateUnbounded< int>();var sourceWriter = source.Writer;IAsyncEnumerable< int>asyncEnumerable = source.Reader.ReadAllAsync();HandlerTask = Task.Run(async()=> {等待foreach(asyncEnumerable中的var项目)Console.WriteLine(item);});等待Task.Yield();等待sourceWriter.WriteAsync(13);var r = await ChildMethod(sourceWriter);sourceWriter.Complete();返回r;}私有异步Task< string>ChildMethod(ChannelWriter< int> sourceWriter){等待sourceWriter.WriteAsync(5);等待Task.Yield();等待sourceWriter.WriteAsync(10);返回你好";}
I'm wondering if there is a way to create either IAsyncEnumerable<T>
or IAsyncEnumerator<T>
via a Source object, rather like TaskCompletionSource
allows one to do for tasks. In particular, TaskCompletionSource
can be passed around like any other parameter.
Maybe something like this:
public class AsyncEnumerables {
public Task HandlerTask { get; set; }
public async Task<string> ParentMethod() {
var source = new AsyncEnumerableSource<int>();
IAsyncEnumerable asyncEnumerable = source.GetAsyncEnumerable();
HandlerTask = Task.Run(() => handleAsyncResultsAsTheyHappen(asyncEnumerable));
int n = await someOtherTask();
source.YieldReturn(n);
var r = await ChildMethod(source);
source.Complete(); // this call would cause the HandlerTask to complete.
return r;
}
private async Task<string> ChildMethod(AsyncEnumerableSource<int> source) {
source.YieldReturn(5);
await SomeOtherCall();
source.YieldReturn(10);
return "hello";
}
}
With the above code, the handleAsyncResultsAsTheyHappen
task would see whatever values got passed into YieldReturn. So it would see the n
from the above code, as well as the 5
and the 10
from ChildMethod
.
You're much better off if you can structure your code to take advantage of yield return
and await foreach
. E.g., this code does almost the same thing:
public async Task Consume()
{
var source = ParentMethod();
HandlerTask = Task.Run(async () => { await foreach (var item in source) { Console.WriteLine(item); } });
}
public async IAsyncEnumerable<int> ParentMethod()
{
await Task.Yield();
yield return 13;
await foreach (var item in ChildMethod())
yield return item;
}
private async IAsyncEnumerable<int> ChildMethod()
{
yield return 5;
await Task.Yield();
yield return 10;
}
However, if you really need an "async enumerable source", you need to first recognize one thing. TaskCompletionSource<T>
holds the results, i.e., the T
(or exception). It's acting as a container. The result can be set before the task is awaited. It's the same thing with the "async enumerable source" - you'd need it to be able to hold results before any items are taken from it. The "async enumerable source" would need to hold multiple results - in this case, a collection.
So what you're actually asking for is "a collection that can be consumed as an asynchronous enumerable". There are a few possibilities here, but the one I'd recommend is a Channel:
public async Task<string> ParentMethod()
{
var source = Channel.CreateUnbounded<int>();
var sourceWriter = source.Writer;
IAsyncEnumerable<int> asyncEnumerable = source.Reader.ReadAllAsync();
HandlerTask = Task.Run(async () => { await foreach (var item in asyncEnumerable) Console.WriteLine(item); });
await Task.Yield();
await sourceWriter.WriteAsync(13);
var r = await ChildMethod(sourceWriter);
sourceWriter.Complete();
return r;
}
private async Task<string> ChildMethod(ChannelWriter<int> sourceWriter)
{
await sourceWriter.WriteAsync(5);
await Task.Yield();
await sourceWriter.WriteAsync(10);
return "hello";
}
这篇关于IAsyncEnumerable或IAsyncEnumerator的工厂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!