C# 等待IEnumerable项目(等待后再等待)
我有一个迭代器-返回类型是C# 等待IEnumerable项目(等待后再等待),c#,.net,linq,asynchronous,async-await,C#,.net,Linq,Asynchronous,Async Await,我有一个迭代器-返回类型是IEnumerable,这样我可以在以后等待每个项目: private IEnumerable<Task<Event>> GetEventsAsync(long length) { var pos = _reader.BaseStream.Position; while (_reader.BaseStream.Position - pos < length) { yield return ReadEv
IEnumerable
,这样我可以在以后等待每个项目:
private IEnumerable<Task<Event>> GetEventsAsync(long length)
{
var pos = _reader.BaseStream.Position;
while (_reader.BaseStream.Position - pos < length)
{
yield return ReadEvent(); // this method is async
}
}
我不想使用Task.whell,因为它会列举所有的东西,而这正是我试图避免的。我想让这个迭代器在传入构造函数之前保持不变。我想推迟执行。(如果这种方法不可行,我将使用工厂方法)
产量
不符合预期,等待,可能下一个c版本将有更好的规定。现在,您只需等待事件并将其存储在列表中。另外,如果您的ReadEvent
依赖于Stream.Position
,则您不能使用Task.whalll
或任何其他方式,而只需在列表中枚举并存储结果
private async Task<IEnumerable<Event>> GetEventsAsync(long length)
{
List<Event> events = new List<Event>();
var pos = _reader.BaseStream.Position;
while (_reader.BaseStream.Position - pos < length)
{
// if ReadEvent depends on _reader.BaseStream.Postion
// you cannot use Task.WhenAll, because it executes all
// tasks in parallel, where else, you must await to finish
// your previous ReadEvent
Event e = await ReadEvent(); // this method is async
events.Add(e);
}
return events;
}
专用异步任务GetEventsAsync(长)
{
列表事件=新列表();
var pos=_reader.BaseStream.Position;
while(_reader.BaseStream.Position-pos
您可以在所有时候使用进行此操作,并异步等待
private async Task<EventManager> ReadEventManagerAsync()
{
// some other stuff
var length = Reverse(await _reader.ReadInt32()); // bytes to read
var events = GetEventsAsync(length); // cant await iterator. so use linq
await Task.WhenAll(events);
return new EventManager(events.Select(x => x.Result));
}
private异步任务ReadEventManagerAsync()
{
//一些其他的东西
var length=Reverse(等待_reader.ReadInt32());//要读取的字节数
var events=GetEventsAsync(length);//不能等待迭代器。所以使用linq
等待任务。何时(事件);
返回新的EventManager(events.Select(x=>x.Result));
}
不,它将同步运行(构造函数毕竟不能是异步的)
这并不意味着如果你从未真正执行过任务,你的表现就会受到影响events.Select(async e=>await e)。Select(x=>x.Result)
最终返回一个可枚举项。它不会调用第一个Select
,这意味着等待的代码永远不会被调用
这段代码会异步运行吗
否。枚举可枚举项时,它将同步运行,并完成
Select(async e=>await e)
什么都不做。这与Select(e=>e)
相同。它是而不是等待e代码>
将流转换为-IEnumerable
的整个过程非常奇怪。也许你想把它转换成IObservable
如果这种方法不可行,我将使用工厂方法
是的,您不能在构造函数中使用wait
,阻塞可能会导致死锁。异步工厂方法可能是最好的选择。如果不在构造函数中枚举此查询,则它将根本不会运行。请显示构造函数代码我理解,我正在构造函数中枚举此查询。我使用了很多自制的方法,所以这并没有真正的帮助。我有这样的东西UnknownEvents=events.sievent(AEvents.sievent(BEvents.ToReadOnlyCollection)(x=>x)代码>这将枚举所有内容@SergeyBerezovskiyyield不能像预期的那样与Wait一起工作,可能下一个c#版本会有更好的规定。现在,您只需等待事件并将其存储在列表中,看看我的答案。另外,如果您的ReadEvent依赖于Stream.Position
,则您不能使用Task.WhenAll
或任何其他方式,而只需将结果枚举并存储在列表中。Task.WhenAll
将并行执行每个操作,makingStream.Position
返回无效的位置。所以,如果我在构造函数中枚举这个,它会同步运行吗?然后,我想我别无选择,只能按照@akashkava的建议将结果存储在列表中,并将列表传递给构造函数。将其强制放入列表将使代码已经运行,所以不确定这是否是您想要的@卡泽马卡里耶先生。我想让事情看起来很酷,(并防止额外的列表创建-无论如何GC将处理它顺便说一句),但我认为这就是我现在所能做的,谢谢你的回答,我接受这两个答案,如果我可以:)
await e;
return e.Result; // is it safe?
private async Task<IEnumerable<Event>> GetEventsAsync(long length)
{
List<Event> events = new List<Event>();
var pos = _reader.BaseStream.Position;
while (_reader.BaseStream.Position - pos < length)
{
// if ReadEvent depends on _reader.BaseStream.Postion
// you cannot use Task.WhenAll, because it executes all
// tasks in parallel, where else, you must await to finish
// your previous ReadEvent
Event e = await ReadEvent(); // this method is async
events.Add(e);
}
return events;
}
private async Task<EventManager> ReadEventManagerAsync()
{
// some other stuff
var length = Reverse(await _reader.ReadInt32()); // bytes to read
var events = GetEventsAsync(length); // cant await iterator. so use linq
await Task.WhenAll(events);
return new EventManager(events.Select(x => x.Result));
}