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