C# 处理来自执行屈服返回函数的线程的值
我是多线程新手,我正在尝试创建一个枚举器,使其在准备就绪时接收一个值,但在后台继续处理 我希望能够像这样使用最后一个类:C# 处理来自执行屈服返回函数的线程的值,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,我是多线程新手,我正在尝试创建一个枚举器,使其在准备就绪时接收一个值,但在后台继续处理 我希望能够像这样使用最后一个类: while (await asyncEnumerator.MoveNextAsync()) { T result = asyncEnum.Current; //Do Something } 但我希望它在我执行while循环时继续获得下一个结果 注释:无法并行处理,因为每个结果取决于之前的结果 我想可能有一个包含结果的队列,让一个线程在返回队
while (await asyncEnumerator.MoveNextAsync())
{
T result = asyncEnum.Current;
//Do Something
}
但我希望它在我执行while循环时继续获得下一个结果
注释:无法并行处理,因为每个结果取决于之前的结果
我想可能有一个包含结果的队列,让一个线程在返回队列中的第一个结果时获取结果,但我无法让它工作。这是我的尝试,但我不知道该怎么做MoveNext()
:
我更新了代码
public class AsyncEnumerator<T>
{
private object _sync = new object();
private readonly Queue<T> _queue;
private readonly IEnumerable<T> _enumerable;
public AsyncEnumerator(IEnumerable<T> enumerable)
{
_enumerable = enumerable;
_queue = new Queue<T>();
}
/// <summary>
/// Start getting results when requested the firstTime
/// </summary>
private bool _startFlag;
public async Task<bool> MoveNextAsync()
{
if (_finished)
{
return false;
}
if (!_startFlag)
{
_startFlag = true;
SetResultsAsync();
}
if (_queue.Count > 0)
{
Current = _queue.Dequeue();
return true;
}
//What here?
return await Task.Run(()=> true);
}
private T _current;
public T Current
{
get
{
lock (_sync)
{
return _current;
}
}
private set { _current = value; }
}
private bool _finished;
private async Task SetResultsAsync()
{
IEnumerator<T> enumerator = _enumerable.GetEnumerator();
bool moveNext = await Task.Run(() => enumerator.MoveNext());
while (moveNext)
{
_queue.Enqueue(enumerator.Current);
moveNext = await Task.Run(() => enumerator.MoveNext());
}
_finished = true;
}
}
公共类异步枚举器
{
私有对象_sync=新对象();
专用只读队列_队列;
私有只读IEnumerable _enumerable;
公共异步枚举器(IEnumerable可枚举)
{
_可枚举=可枚举;
_队列=新队列();
}
///
///在第一次请求时开始获取结果
///
私人图书馆;
公共异步任务MoveNextAsync()
{
如果(_完成)
{
返回false;
}
如果(!\u startFlag)
{
_startFlag=true;
SetResultsAsync();
}
如果(_queue.Count>0)
{
当前=_queue.Dequeue();
返回true;
}
//这是什么?
返回等待任务。运行(()=>true);
}
私人T_电流;
公共电流
{
收到
{
锁定(同步)
{
返回电流;
}
}
私有集{u current=value;}
}
私人住宅完工;
专用异步任务SetResultsAsync()
{
IEnumerator枚举器=_enumerable.GetEnumerator();
bool moveNext=wait Task.Run(()=>enumerator.moveNext());
while(移动下一步)
{
_queue.Enqueue(枚举数.Current);
moveNext=wait Task.Run(()=>enumerator.moveNext());
}
_完成=正确;
}
}
显然,如果有更好的方法来做这件事,我想知道,我是新的多线程
但我希望它在我执行while循环时继续获得下一个结果
普通异步枚举器在这里是错误的解决方案。枚举器是一种“拉”技术;它们仅在消费代码请求下一项时才执行操作
从“生产者”和“消费者”的角度思考你的问题。如果生产者仅在消费者请求时才工作,则您有一个枚举器场景。在您的例子中,您希望生产者独立地生产项目,因此枚举器不能正确地匹配
一种选择是;可观测值表示类似于枚举数的值序列,只是可观测值是一种“推”技术。因此,生产者将向消费者推送价值观,消费者对新的价值观做出反应(因此称为反应型)
听起来Rx非常适合你,但它确实有相当高的学习曲线
更简单的选择可能是使用更传统的生产者/消费者队列。因为您希望异步使用它,所以您需要一个异步兼容的生产者/消费者队列。是的,因为是从
在这两种情况下,您都会先启动生产商,然后消费:
var queue = new BufferBlock<T>();
// Kick off producer
var producer = Task.Run(() =>
{
while (...)
{
T value = ...;
queue.Post(value);
}
queue.Complete();
});
// Consumer code
while (await queue.OutputAvailableAsync())
{
var value = await queue.ReceiveAsync();
...
}
var queue=new BufferBlock();
//开球制作人
var producer=Task.Run(()=>
{
而(…)
{
T值=。。。;
queue.Post(值);
}
queue.Complete();
});
//消费者代码
while(wait queue.OutputAvailableAsync())
{
var value=wait queue.ReceiveAsync();
...
}
最后,您将希望
等待该生产者
任务,这样您就可以正确地检测生产者代码中的任何异常。您不应该使用异步无效方法,这很可能会给您带来问题。使MoveNextAsync异步并使SetResultAsync返回任务。顺便说一句,有一个IAsyncEnumerable
和一个IAsyncEnumerator
。@CamiloTerevinto仍然不能帮助我使用MoveNextAsync()
。。。我修复了CodeSetResultsSync中的问题,MoveNextAsync中缺少等待。除此之外,如果队列为空,是否意味着所有项目都已处理?您将返回false代码>在这种情况下,使用正确的工具和正确的模式。看起来您需要的是生产者/消费者模式,查找BlockingCollection“我希望它在while循环中执行任务时继续获得下一个结果”——并发计算(即“执行任务”)需要多个线程。它也不需要等待。但是等待
等待。如果您想要并发操作,为什么要编写非并发代码?我同意前面的评论,可能您只需要一个任务。运行()
将数据馈送到BlockingCollection
实例,并在getconsumineGenumerable()
上循环以检索并处理该数据。但你到底在问什么还不清楚。你为什么要等待两次?一次还不够吗?从技术上讲,是的,一旦OutputAvailableAsync
返回true
,那么下一个ReceiveAsync
将同步完成,因此您可以使用Receive
。为了保持一致性,我只使用了ReceiveAsync
。