C# 链接异步/等待

C# 链接异步/等待,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,我开发了许多算法,这些算法通过使用常规线程自行完成大部分线程。方法始终如下 float[] GetData(int requestedItemIndex) 使用上述方法,索引被推送到一些消息队列中,这些消息队列由inidividual算法的线程处理。所以最后算法的界面是这样的: public abstract class AlgorithmBase { private readonly AlgorithmBase Parent; private void RequestQue

我开发了许多算法,这些算法通过使用常规
线程
自行完成大部分线程。方法始终如下

float[] GetData(int requestedItemIndex)
使用上述方法,索引被推送到一些消息队列中,这些消息队列由inidividual算法的线程处理。所以最后算法的界面是这样的:

public abstract class AlgorithmBase
{
    private readonly AlgorithmBase Parent;

    private void RequestQueue()
    {
    }

    public float[] GetData(int requestedItemIndex) => Parent.GetData(requestedItemIndex);
}
  public abstract class AlgorithmBase
    {
        private readonly AlgorithmBase Parent;


        public async Task<float[]> GetDataAsync(int requestedItemIndex, CancellationToken token = default)
        {
            var data = await Parent.GetDataAsync(requestedItemIndex);

            return await Task.Run<float[]>(async () => ProcessData());
        }            
    }
这个例子很简单,但只是为了得到线索。问题是,我可以链接目前与我的解决方案配合良好的算法。正如您所看到的,每个GetData调用父算法的另一个GetData。这当然会变得更复杂,当然需要有一个最终的父级作为数据源,否则我会得到StackOverflowExceptions

现在,我尝试使用async/await来改变这种行为。我的问题是,如果我重写代码,我会得到如下结果:

public abstract class AlgorithmBase
{
    private readonly AlgorithmBase Parent;

    private void RequestQueue()
    {
    }

    public float[] GetData(int requestedItemIndex) => Parent.GetData(requestedItemIndex);
}
  public abstract class AlgorithmBase
    {
        private readonly AlgorithmBase Parent;


        public async Task<float[]> GetDataAsync(int requestedItemIndex, CancellationToken token = default)
        {
            var data = await Parent.GetDataAsync(requestedItemIndex);

            return await Task.Run<float[]>(async () => ProcessData());
        }            
    }
公共抽象类算法库
{
私有只读算法库父级;
公共异步任务GetDataAsync(int-RequestEditedIndex,CancellationToken-token=default)
{
var data=await Parent.GetDataAsync(requestedItemIndex);
返回wait Task.Run(异步()=>ProcessData());
}            
}
现在,我已经链接了算法,任何新的算法都会跨越另一个任务,这在多次执行时可能会非常耗时


因此,我的问题是,是否有一种方法可以通过使用定义接口将下一个任务嵌入到已经运行的任务中?

无需显式使用
任务。运行
。您应该避免这种情况,并将选择权留给
AlgorithmBase
类的使用者

因此,您可以非常类似地实现
async
版本,其中
Task
对象将从父对象传播到子对象:

public abstract class AlgorithmBase
{
    private readonly AlgorithmBase Parent;

    private void RequestQueue()
    {
    }

    public Task<float[]> GetDataAsync(int requestedItemIndex) 
         => Parent.GetDataAsync(requestedItemIndex);
}
最后,
SortAlogirthm
的消费者可以决定是等待它,还是直接开火并忘记它

var algo = new SortAlgorithm();

// asynchronously wait until it's finished
var data = await algo.GetDataAsync(1);

// start processing without waiting for the result
algo.GetDataAsync(1);

// not needed - GetDataAsync already returns Task, Task.Run is not needed in this case
Task.Run(() => algo.GetDataAsync(1));

当在库中等待代码时,您通常希望每次都这样做,尤其是在循环中等待时。因此,为了提高你的库的性能,考虑使用所有的<代码>等待< /COD> S.< /P>任务是任务,任务调度程序可能在CPU绑定和IO绑定的工作负载中比你能更好地管理它们。我不确定到底是什么问题。如果您想要管道化数据和工作流,最好查看数据流或工作流RX@TheGeneral:我查看了这两种解决方案(数据流和Rx)。我的问题是我所有的需求都是基于拉的,而不是基于推的。@GSerg:谢谢你的评论。老实说,我没有测试代码,只是为了解释而插入了它。@GSerg假设
ProcessData
是一个同步方法,示例代码将产生一个警告(因为有一个
async
没有
await
),但是该方法的结果将被很好地等待。理解异步委托。@TheodorZoulias因为某种原因在我脑海中闪过。试着不要考虑线程,而要考虑任务。每个任务都将在从线程池获取的可用线程上调用,因此后面的线程由框架管理。如果ProcessData()是CPU绑定的,则必须在某个位置使用task.Run()。