我怎样才能让`计谋......`工作与`产量return`(即一个迭代方法中)? [英] How can I make `await …` work with `yield return` (i.e. inside an iterator method)?
问题描述
我有现有的code,类似于:
I have existing code that looks similar to:
IEnumerable<SomeClass> GetStuff()
{
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn)
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
SomeClass someClass = f(reader); // create instance based on returned row
yield return someClass;
}
}
}
我似乎可以通过使用受益 reader.ReadAsync()
。但是,如果我只是修改了一行:
It seems I could benefit by using reader.ReadAsync()
. However, if I just modify the one line:
while (await reader.ReadAsync())
编译器告诉我,等待
只能在标有方法异步
使用,并建议我修改方法签名是:
the compiler informs me that await
can only be used in methods marked with async
, and suggests I modify the method signature to be:
async Task<IEnumerable<SomeClass>> GetStuff()
然而,这样做使得 GetStuff()
不可用,因为:
的GetStuff()身体
不能是迭代器块,因为任务&LT; IEnumerable的&LT; SomeClass的&GT;&GT;
不是一个迭代器接口类型。的
The body of
GetStuff()
cannot be an iterator block becauseTask<IEnumerable<SomeClass>>
is not an iterator interface type.
我敢肯定,我缺少的异步编程模型的一个重要概念。
I'm sure I am missing a key concept with the async programming model.
问题:
- 我可以使用
ReadAsync()
在我的迭代器?怎么样? - 如何看待异步模式不同,因此,我理解它是如何工作在这种情况?
- Can I use
ReadAsync()
in my iterator? How? - How can I think about the async paradigm differently so that I understand how it works in this type of situation?
推荐答案
现在的问题是你问实际上并没有太大的意义。 的IEnumerable&LT; T&GT;
是一个同步接口,并返回任务&LT; IEnumerable的&LT; T&GT;&GT;
不会帮你多少,因为一些线程将不得不阻塞等待每一个项目,不管是什么。
The problem is what you're asking doesn't actually make much sense. IEnumerable<T>
is a synchronous interface, and returning Task<IEnumerable<T>>
isn't going to help you much, because some thread would have to block waiting for each item, no matter what.
你真的想回到的是一些异步替代的IEnumerable&LT; T&GT;
:像的IObservable&LT; T&GT;
,从TPL数据流或 IAsyncEnumerable&LT数据流块; T&GT;
。
What you actually want to return is some asynchronous alternative to IEnumerable<T>
: something like IObservable<T>
, dataflow block from TPL Dataflow or IAsyncEnumerable<T>
.
使用TPL数据流,要做到这一点的一种方法是:
Using TPL Dataflow, one way to do this would be:
ISourceBlock<SomeClass> GetStuff() {
var block = new BufferBlock<SomeClass>();
Task.Run(async () =>
{
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
await conn.OpenAsync();
SqlDataReader reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
SomeClass someClass;
// Create an instance of SomeClass based on row returned.
block.Post(someClass);
}
block.Complete();
}
});
return block;
}
您可能会需要添加错误处理上述code,但除此之外,它应该工作,这将是完全异步的。
You'll probably want to add error handling to the above code, but otherwise, it should work and it will be completely asynchronous.
你的code其余部分将随后使用来自返回块中的项目也以异步方式,可能使用 ActionBlock
。
The rest of your code would then consume items from the returned block also asynchronously, probably using ActionBlock
.
这篇关于我怎样才能让`计谋......`工作与`产量return`(即一个迭代方法中)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!